coder-config 0.40.1
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 +553 -0
- package/cli.js +431 -0
- package/config-loader.js +294 -0
- package/hooks/activity-track.sh +56 -0
- package/hooks/codex-workstream.sh +44 -0
- package/hooks/gemini-workstream.sh +44 -0
- package/hooks/workstream-inject.sh +20 -0
- package/lib/activity.js +283 -0
- package/lib/apply.js +344 -0
- package/lib/cli.js +267 -0
- package/lib/config.js +171 -0
- package/lib/constants.js +55 -0
- package/lib/env.js +114 -0
- package/lib/index.js +47 -0
- package/lib/init.js +122 -0
- package/lib/mcps.js +139 -0
- package/lib/memory.js +201 -0
- package/lib/projects.js +138 -0
- package/lib/registry.js +83 -0
- package/lib/utils.js +129 -0
- package/lib/workstreams.js +652 -0
- package/package.json +80 -0
- package/scripts/capture-screenshots.js +142 -0
- package/scripts/postinstall.js +122 -0
- package/scripts/release.sh +71 -0
- package/scripts/sync-version.js +77 -0
- package/scripts/tauri-prepare.js +328 -0
- package/shared/mcp-registry.json +76 -0
- package/ui/dist/assets/index-DbZ3_HBD.js +3204 -0
- package/ui/dist/assets/index-DjLdm3Mr.css +32 -0
- package/ui/dist/icons/icon-192.svg +16 -0
- package/ui/dist/icons/icon-512.svg +16 -0
- package/ui/dist/index.html +39 -0
- package/ui/dist/manifest.json +25 -0
- package/ui/dist/sw.js +24 -0
- package/ui/dist/tutorial/claude-settings.png +0 -0
- package/ui/dist/tutorial/header.png +0 -0
- package/ui/dist/tutorial/mcp-registry.png +0 -0
- package/ui/dist/tutorial/memory-view.png +0 -0
- package/ui/dist/tutorial/permissions.png +0 -0
- package/ui/dist/tutorial/plugins-view.png +0 -0
- package/ui/dist/tutorial/project-explorer.png +0 -0
- package/ui/dist/tutorial/projects-view.png +0 -0
- package/ui/dist/tutorial/sidebar.png +0 -0
- package/ui/dist/tutorial/tutorial-view.png +0 -0
- package/ui/dist/tutorial/workstreams-view.png +0 -0
- package/ui/routes/activity.js +58 -0
- package/ui/routes/commands.js +74 -0
- package/ui/routes/configs.js +329 -0
- package/ui/routes/env.js +40 -0
- package/ui/routes/file-explorer.js +668 -0
- package/ui/routes/index.js +41 -0
- package/ui/routes/mcp-discovery.js +235 -0
- package/ui/routes/memory.js +385 -0
- package/ui/routes/package.json +3 -0
- package/ui/routes/plugins.js +466 -0
- package/ui/routes/projects.js +198 -0
- package/ui/routes/registry.js +30 -0
- package/ui/routes/rules.js +74 -0
- package/ui/routes/search.js +125 -0
- package/ui/routes/settings.js +381 -0
- package/ui/routes/subprojects.js +208 -0
- package/ui/routes/tool-sync.js +127 -0
- package/ui/routes/updates.js +339 -0
- package/ui/routes/workstreams.js +224 -0
- package/ui/server.cjs +773 -0
- package/ui/terminal-server.cjs +160 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Terminal Server
|
|
3
|
+
* Provides PTY-based terminal sessions over WebSocket
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const WebSocket = require('ws');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
let pty;
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
pty = require('node-pty');
|
|
12
|
+
} catch (e) {
|
|
13
|
+
console.warn('node-pty not available, terminal features disabled');
|
|
14
|
+
pty = null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class TerminalServer {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.sessions = new Map(); // sessionId -> { pty, ws }
|
|
20
|
+
this.wss = null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Attach WebSocket server to an existing HTTP server
|
|
25
|
+
*/
|
|
26
|
+
attach(httpServer) {
|
|
27
|
+
if (!pty) {
|
|
28
|
+
console.warn('Terminal server disabled: node-pty not available');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
this.wss = new WebSocket.Server({
|
|
33
|
+
server: httpServer,
|
|
34
|
+
path: '/ws/terminal'
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
this.wss.on('connection', (ws, req) => {
|
|
38
|
+
const sessionId = this.generateSessionId();
|
|
39
|
+
console.log(`Terminal session ${sessionId} connected`);
|
|
40
|
+
|
|
41
|
+
// Parse query params for initial command and cwd
|
|
42
|
+
const url = new URL(req.url, 'http://localhost');
|
|
43
|
+
const cwd = url.searchParams.get('cwd') || process.cwd();
|
|
44
|
+
const cmd = url.searchParams.get('cmd') || null;
|
|
45
|
+
|
|
46
|
+
// Create PTY with error handling
|
|
47
|
+
let ptyProcess;
|
|
48
|
+
try {
|
|
49
|
+
const shell = process.env.SHELL || (os.platform() === 'win32' ? 'powershell.exe' : 'bash');
|
|
50
|
+
ptyProcess = pty.spawn(shell, [], {
|
|
51
|
+
name: 'xterm-256color',
|
|
52
|
+
cols: 80,
|
|
53
|
+
rows: 24,
|
|
54
|
+
cwd: cwd,
|
|
55
|
+
env: {
|
|
56
|
+
...process.env,
|
|
57
|
+
TERM: 'xterm-256color',
|
|
58
|
+
COLORTERM: 'truecolor',
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
} catch (err) {
|
|
62
|
+
console.error('Failed to spawn PTY:', err.message);
|
|
63
|
+
ws.send(JSON.stringify({ type: 'error', message: 'Failed to start terminal: ' + err.message }));
|
|
64
|
+
ws.close();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.sessions.set(sessionId, { pty: ptyProcess, ws });
|
|
69
|
+
|
|
70
|
+
// Send session ID to client
|
|
71
|
+
ws.send(JSON.stringify({ type: 'session', sessionId }));
|
|
72
|
+
|
|
73
|
+
// If initial command provided, execute it after a short delay
|
|
74
|
+
if (cmd) {
|
|
75
|
+
setTimeout(() => {
|
|
76
|
+
ptyProcess.write(cmd + '\r');
|
|
77
|
+
}, 500);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// PTY output -> WebSocket
|
|
81
|
+
ptyProcess.onData((data) => {
|
|
82
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
83
|
+
ws.send(JSON.stringify({ type: 'output', data }));
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// PTY exit
|
|
88
|
+
ptyProcess.onExit(({ exitCode, signal }) => {
|
|
89
|
+
console.log(`Terminal session ${sessionId} exited (code: ${exitCode}, signal: ${signal})`);
|
|
90
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
91
|
+
ws.send(JSON.stringify({ type: 'exit', exitCode, signal }));
|
|
92
|
+
}
|
|
93
|
+
this.sessions.delete(sessionId);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// WebSocket messages -> PTY
|
|
97
|
+
ws.on('message', (message) => {
|
|
98
|
+
try {
|
|
99
|
+
const msg = JSON.parse(message.toString());
|
|
100
|
+
|
|
101
|
+
switch (msg.type) {
|
|
102
|
+
case 'input':
|
|
103
|
+
ptyProcess.write(msg.data);
|
|
104
|
+
break;
|
|
105
|
+
|
|
106
|
+
case 'resize':
|
|
107
|
+
if (msg.cols && msg.rows) {
|
|
108
|
+
ptyProcess.resize(msg.cols, msg.rows);
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
|
|
112
|
+
case 'kill':
|
|
113
|
+
ptyProcess.kill();
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
} catch (e) {
|
|
117
|
+
console.error('Terminal message parse error:', e);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// WebSocket close
|
|
122
|
+
ws.on('close', () => {
|
|
123
|
+
console.log(`Terminal session ${sessionId} WebSocket closed`);
|
|
124
|
+
const session = this.sessions.get(sessionId);
|
|
125
|
+
if (session) {
|
|
126
|
+
session.pty.kill();
|
|
127
|
+
this.sessions.delete(sessionId);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// WebSocket error
|
|
132
|
+
ws.on('error', (err) => {
|
|
133
|
+
console.error(`Terminal session ${sessionId} error:`, err);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
console.log('Terminal WebSocket server attached at /ws/terminal');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
generateSessionId() {
|
|
141
|
+
return Math.random().toString(36).substring(2, 15);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Close all sessions and the WebSocket server
|
|
146
|
+
*/
|
|
147
|
+
close() {
|
|
148
|
+
for (const [sessionId, session] of this.sessions) {
|
|
149
|
+
session.pty.kill();
|
|
150
|
+
session.ws.close();
|
|
151
|
+
}
|
|
152
|
+
this.sessions.clear();
|
|
153
|
+
|
|
154
|
+
if (this.wss) {
|
|
155
|
+
this.wss.close();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = TerminalServer;
|