orc-server 1.0.5

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 (37) hide show
  1. package/dist/__tests__/auth.test.js +49 -0
  2. package/dist/__tests__/watcher.test.js +58 -0
  3. package/dist/claude/chatService.js +175 -0
  4. package/dist/claude/sessionBrowser.js +743 -0
  5. package/dist/claude/watcher.js +242 -0
  6. package/dist/config.js +44 -0
  7. package/dist/files/browser.js +227 -0
  8. package/dist/files/reader.js +159 -0
  9. package/dist/files/search.js +124 -0
  10. package/dist/git/gitHandler.js +177 -0
  11. package/dist/git/gitService.js +299 -0
  12. package/dist/git/index.js +8 -0
  13. package/dist/http/server.js +96 -0
  14. package/dist/index.js +77 -0
  15. package/dist/ssh/index.js +9 -0
  16. package/dist/ssh/sshHandler.js +205 -0
  17. package/dist/ssh/sshManager.js +329 -0
  18. package/dist/terminal/index.js +11 -0
  19. package/dist/terminal/localTerminalHandler.js +176 -0
  20. package/dist/terminal/localTerminalManager.js +497 -0
  21. package/dist/terminal/terminalWebSocket.js +136 -0
  22. package/dist/types.js +2 -0
  23. package/dist/utils/logger.js +42 -0
  24. package/dist/websocket/auth.js +18 -0
  25. package/dist/websocket/server.js +631 -0
  26. package/package.json +66 -0
  27. package/web-dist/assets/highlight-l0sNRNKZ.js +1 -0
  28. package/web-dist/assets/index-C8TJGN-T.css +41 -0
  29. package/web-dist/assets/index-DjLLxjMD.js +39 -0
  30. package/web-dist/assets/markdown-C_j0ZeeY.js +51 -0
  31. package/web-dist/assets/react-vendor-CqP5oCk4.js +9 -0
  32. package/web-dist/assets/xterm-BCk906R6.js +9 -0
  33. package/web-dist/icon-192.png +0 -0
  34. package/web-dist/icon-512.png +0 -0
  35. package/web-dist/index.html +23 -0
  36. package/web-dist/manifest.json +24 -0
  37. package/web-dist/sw.js +35 -0
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createHttpServer = createHttpServer;
7
+ const express_1 = __importDefault(require("express"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const config_1 = require("../config");
11
+ const logger_1 = require("../utils/logger");
12
+ const MIME_TYPES = {
13
+ '.pdf': 'application/pdf',
14
+ '.png': 'image/png',
15
+ '.jpg': 'image/jpeg',
16
+ '.jpeg': 'image/jpeg',
17
+ '.gif': 'image/gif',
18
+ '.webp': 'image/webp',
19
+ '.svg': 'image/svg+xml',
20
+ '.bmp': 'image/bmp',
21
+ '.ico': 'image/x-icon',
22
+ };
23
+ function authenticateRequest(req) {
24
+ const token = req.query.token;
25
+ if (token && token === config_1.CONFIG.authToken)
26
+ return true;
27
+ const authHeader = req.headers.authorization;
28
+ if (authHeader === `Bearer ${config_1.CONFIG.authToken}`)
29
+ return true;
30
+ return !config_1.CONFIG.authToken; // allow if no token configured
31
+ }
32
+ function createHttpServer() {
33
+ const app = (0, express_1.default)();
34
+ app.get('/health', (_req, res) => {
35
+ res.json({ status: 'ok', timestamp: Date.now() });
36
+ });
37
+ app.get('/token', (req, res) => {
38
+ const authHeader = req.headers.authorization;
39
+ if (authHeader !== `Bearer ${config_1.CONFIG.authToken}`) {
40
+ res.status(401).json({ error: 'Unauthorized' });
41
+ return;
42
+ }
43
+ res.json({ token: config_1.CONFIG.authToken });
44
+ });
45
+ // File serving endpoint for PDF/image preview
46
+ app.get('/api/file', (req, res) => {
47
+ res.setHeader('Access-Control-Allow-Origin', '*');
48
+ if (!authenticateRequest(req)) {
49
+ res.status(401).json({ error: 'Unauthorized' });
50
+ return;
51
+ }
52
+ const filePath = req.query.path;
53
+ if (!filePath) {
54
+ res.status(400).json({ error: 'Missing path parameter' });
55
+ return;
56
+ }
57
+ const resolved = path_1.default.resolve(filePath);
58
+ const ext = path_1.default.extname(resolved).toLowerCase();
59
+ const mimeType = MIME_TYPES[ext];
60
+ if (!mimeType) {
61
+ res.status(400).json({ error: 'Unsupported file type' });
62
+ return;
63
+ }
64
+ let stat;
65
+ try {
66
+ stat = fs_1.default.statSync(resolved);
67
+ }
68
+ catch {
69
+ res.status(404).json({ error: 'File not found' });
70
+ return;
71
+ }
72
+ if (stat.size > config_1.CONFIG.maxFileSize) {
73
+ res.status(413).json({ error: 'File too large' });
74
+ return;
75
+ }
76
+ res.setHeader('Content-Type', mimeType);
77
+ res.setHeader('Content-Disposition', 'inline');
78
+ res.setHeader('Content-Length', stat.size);
79
+ fs_1.default.createReadStream(resolved).pipe(res);
80
+ });
81
+ // Serve web client static files
82
+ const webDistPath = process.env.WEB_DIST_PATH
83
+ || path_1.default.join(__dirname, '../../web-dist');
84
+ if (fs_1.default.existsSync(webDistPath)) {
85
+ logger_1.logger.info(`Serving web client from ${webDistPath}`);
86
+ app.use(express_1.default.static(webDistPath));
87
+ app.get('{*path}', (_req, res) => {
88
+ res.sendFile(path_1.default.join(webDistPath, 'index.html'));
89
+ });
90
+ }
91
+ const httpPort = config_1.CONFIG.port + 1;
92
+ app.listen(httpPort, config_1.CONFIG.host, () => {
93
+ logger_1.logger.info(`HTTP server running on ${config_1.CONFIG.host}:${httpPort}`);
94
+ });
95
+ return app;
96
+ }
package/dist/index.js ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const server_1 = require("./websocket/server");
5
+ const watcher_1 = require("./claude/watcher");
6
+ const server_2 = require("./http/server");
7
+ const logger_1 = require("./utils/logger");
8
+ class RemoteDevServer {
9
+ constructor() {
10
+ this.wsServer = new server_1.WebSocketServer();
11
+ this.claudeWatcher = new watcher_1.ClaudeWatcher();
12
+ (0, server_2.createHttpServer)();
13
+ this.setupClaudeWatcher();
14
+ }
15
+ setupClaudeWatcher() {
16
+ this.claudeWatcher.on('user_input', (data) => {
17
+ this.wsServer.broadcast({
18
+ type: 'claude_user_input',
19
+ data
20
+ });
21
+ });
22
+ this.claudeWatcher.on('assistant_message', (data) => {
23
+ this.wsServer.broadcast({
24
+ type: 'claude_assistant_message',
25
+ data
26
+ });
27
+ });
28
+ this.claudeWatcher.on('tool_call', (data) => {
29
+ this.wsServer.broadcast({
30
+ type: 'claude_tool_call',
31
+ data
32
+ });
33
+ });
34
+ this.claudeWatcher.on('tool_result', (data) => {
35
+ this.wsServer.broadcast({
36
+ type: 'claude_tool_result',
37
+ data
38
+ });
39
+ });
40
+ this.claudeWatcher.on('file_change', (data) => {
41
+ this.wsServer.broadcast({
42
+ type: 'claude_file_change',
43
+ data
44
+ });
45
+ });
46
+ this.claudeWatcher.on('progress', (data) => {
47
+ this.wsServer.broadcast({
48
+ type: 'claude_progress',
49
+ data
50
+ });
51
+ });
52
+ }
53
+ async start() {
54
+ logger_1.logger.info('Starting Remote Dev Server');
55
+ await this.claudeWatcher.start();
56
+ logger_1.logger.info('Server ready');
57
+ }
58
+ stop() {
59
+ logger_1.logger.info('Stopping Remote Dev Server');
60
+ this.claudeWatcher.stop();
61
+ }
62
+ }
63
+ const server = new RemoteDevServer();
64
+ server.start().catch((error) => {
65
+ logger_1.logger.error('Failed to start server:', error);
66
+ process.exit(1);
67
+ });
68
+ process.on('SIGINT', () => {
69
+ logger_1.logger.info('Received SIGINT, shutting down');
70
+ server.stop();
71
+ process.exit(0);
72
+ });
73
+ process.on('SIGTERM', () => {
74
+ logger_1.logger.info('Received SIGTERM, shutting down');
75
+ server.stop();
76
+ process.exit(0);
77
+ });
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SSHHandler = exports.sshManager = exports.SSHConnection = exports.SSHManager = void 0;
4
+ var sshManager_1 = require("./sshManager");
5
+ Object.defineProperty(exports, "SSHManager", { enumerable: true, get: function () { return sshManager_1.SSHManager; } });
6
+ Object.defineProperty(exports, "SSHConnection", { enumerable: true, get: function () { return sshManager_1.SSHConnection; } });
7
+ Object.defineProperty(exports, "sshManager", { enumerable: true, get: function () { return sshManager_1.sshManager; } });
8
+ var sshHandler_1 = require("./sshHandler");
9
+ Object.defineProperty(exports, "SSHHandler", { enumerable: true, get: function () { return sshHandler_1.SSHHandler; } });
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SSHHandler = void 0;
4
+ const logger_1 = require("../utils/logger");
5
+ const sshManager_1 = require("./sshManager");
6
+ /**
7
+ * Handles SSH-related WebSocket messages.
8
+ * Routes ssh_* messages to the appropriate SSHManager methods.
9
+ * Supports multiple shell sessions per client via sessionId.
10
+ */
11
+ class SSHHandler {
12
+ constructor(sendFn) {
13
+ this.sendFn = sendFn;
14
+ }
15
+ /**
16
+ * Check if this handler should process the message.
17
+ */
18
+ canHandle(messageType) {
19
+ return messageType.startsWith('ssh_');
20
+ }
21
+ /**
22
+ * Process an SSH message.
23
+ */
24
+ async handle(ws, clientId, message) {
25
+ switch (message.type) {
26
+ case 'ssh_connect':
27
+ await this.handleConnect(ws, clientId, message);
28
+ break;
29
+ case 'ssh_start_shell':
30
+ await this.handleStartShell(ws, clientId, message);
31
+ break;
32
+ case 'ssh_input':
33
+ this.handleInput(clientId, message);
34
+ break;
35
+ case 'ssh_resize':
36
+ this.handleResize(clientId, message);
37
+ break;
38
+ case 'ssh_disconnect':
39
+ this.handleDisconnect(ws, clientId);
40
+ break;
41
+ case 'ssh_close_shell':
42
+ this.handleCloseShell(ws, clientId, message);
43
+ break;
44
+ case 'ssh_list_shells':
45
+ this.handleListShells(ws, clientId);
46
+ break;
47
+ case 'ssh_port_forward':
48
+ await this.handlePortForward(ws, clientId, message);
49
+ break;
50
+ case 'ssh_stop_port_forward':
51
+ this.handleStopPortForward(ws, clientId, message);
52
+ break;
53
+ default:
54
+ logger_1.logger.warn(`Unknown SSH message type: ${message.type}`);
55
+ }
56
+ }
57
+ async handleConnect(ws, clientId, message) {
58
+ try {
59
+ const { host, port, username, privateKey, password } = message.data;
60
+ logger_1.logger.info(`SSH connect request: host=${host}, port=${port}, username=${username}, hasPassword=${!!password}, hasPrivateKey=${!!privateKey}`);
61
+ const connection = sshManager_1.sshManager.getConnection(clientId);
62
+ await connection.connect({ host, port, username, privateKey, password });
63
+ this.sendFn(ws, {
64
+ type: 'ssh_connect_response',
65
+ data: { success: true },
66
+ });
67
+ }
68
+ catch (error) {
69
+ logger_1.logger.error('SSH connect error:', error);
70
+ this.sendFn(ws, {
71
+ type: 'ssh_connect_response',
72
+ data: { success: false, message: error.message },
73
+ });
74
+ }
75
+ }
76
+ async handleStartShell(ws, clientId, message) {
77
+ try {
78
+ const connection = sshManager_1.sshManager.getConnection(clientId);
79
+ if (!connection.isConnected()) {
80
+ this.sendFn(ws, {
81
+ type: 'ssh_status',
82
+ data: { status: 'error', message: 'SSH not connected' },
83
+ });
84
+ return;
85
+ }
86
+ const sessionId = message.data?.sessionId || 'default';
87
+ const cols = message.data?.cols || 80;
88
+ const rows = message.data?.rows || 24;
89
+ await connection.startShell(sessionId, (data) => {
90
+ this.sendFn(ws, { type: 'ssh_output', data: { sessionId, output: data } });
91
+ }, () => {
92
+ this.sendFn(ws, {
93
+ type: 'ssh_shell_closed',
94
+ data: { sessionId },
95
+ });
96
+ }, cols, rows);
97
+ this.sendFn(ws, {
98
+ type: 'ssh_shell_started',
99
+ data: { sessionId },
100
+ });
101
+ }
102
+ catch (error) {
103
+ logger_1.logger.error('SSH start shell error:', error);
104
+ this.sendFn(ws, {
105
+ type: 'ssh_status',
106
+ data: { status: 'error', message: error.message },
107
+ });
108
+ }
109
+ }
110
+ handleInput(clientId, message) {
111
+ const connection = sshManager_1.sshManager.getConnection(clientId);
112
+ if (connection.isConnected()) {
113
+ const sessionId = message.data?.sessionId || 'default';
114
+ const input = message.data?.input || message.data;
115
+ // Try new API first, fall back to legacy
116
+ if (!connection.writeToShell(sessionId, typeof input === 'string' ? input : input.input)) {
117
+ // Legacy fallback
118
+ connection.write(typeof input === 'string' ? input : input.input);
119
+ }
120
+ }
121
+ }
122
+ handleResize(clientId, message) {
123
+ const connection = sshManager_1.sshManager.getConnection(clientId);
124
+ if (connection.isConnected()) {
125
+ const sessionId = message.data?.sessionId;
126
+ const cols = message.data.cols;
127
+ const rows = message.data.rows;
128
+ if (sessionId) {
129
+ connection.resizeShell(sessionId, cols, rows);
130
+ }
131
+ else {
132
+ // Legacy fallback
133
+ connection.resize(cols, rows);
134
+ }
135
+ }
136
+ }
137
+ handleCloseShell(ws, clientId, message) {
138
+ const connection = sshManager_1.sshManager.getConnection(clientId);
139
+ const sessionId = message.data?.sessionId;
140
+ if (sessionId && connection.isConnected()) {
141
+ const closed = connection.closeShell(sessionId);
142
+ this.sendFn(ws, {
143
+ type: 'ssh_shell_closed',
144
+ data: { sessionId, success: closed },
145
+ });
146
+ }
147
+ }
148
+ handleListShells(ws, clientId) {
149
+ const connection = sshManager_1.sshManager.getConnection(clientId);
150
+ const shells = connection.isConnected() ? connection.getActiveShells() : [];
151
+ this.sendFn(ws, {
152
+ type: 'ssh_list_shells_response',
153
+ data: { shells },
154
+ });
155
+ }
156
+ handleDisconnect(ws, clientId) {
157
+ sshManager_1.sshManager.removeConnection(clientId);
158
+ this.sendFn(ws, {
159
+ type: 'ssh_status',
160
+ data: { status: 'disconnected', message: 'Disconnected' },
161
+ });
162
+ }
163
+ async handlePortForward(ws, clientId, message) {
164
+ try {
165
+ const { localPort, remoteHost, remotePort } = message.data;
166
+ const connection = sshManager_1.sshManager.getConnection(clientId);
167
+ if (!connection.isConnected()) {
168
+ this.sendFn(ws, {
169
+ type: 'ssh_port_forward_response',
170
+ data: { success: false, localPort, message: 'SSH not connected' },
171
+ });
172
+ return;
173
+ }
174
+ await connection.setupPortForward({ localPort, remoteHost, remotePort });
175
+ this.sendFn(ws, {
176
+ type: 'ssh_port_forward_response',
177
+ data: { success: true, localPort },
178
+ });
179
+ }
180
+ catch (error) {
181
+ logger_1.logger.error('SSH port forward error:', error);
182
+ this.sendFn(ws, {
183
+ type: 'ssh_port_forward_response',
184
+ data: { success: false, localPort: message.data.localPort, message: error.message },
185
+ });
186
+ }
187
+ }
188
+ handleStopPortForward(ws, clientId, message) {
189
+ const connection = sshManager_1.sshManager.getConnection(clientId);
190
+ if (connection.isConnected()) {
191
+ connection.stopPortForward(message.data.localPort);
192
+ }
193
+ this.sendFn(ws, {
194
+ type: 'ssh_port_forward_response',
195
+ data: { success: true, localPort: message.data.localPort, message: 'Port forward stopped' },
196
+ });
197
+ }
198
+ /**
199
+ * Clean up SSH resources for a disconnected client.
200
+ */
201
+ cleanup(clientId) {
202
+ sshManager_1.sshManager.removeConnection(clientId);
203
+ }
204
+ }
205
+ exports.SSHHandler = SSHHandler;