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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +553 -0
  3. package/cli.js +431 -0
  4. package/config-loader.js +294 -0
  5. package/hooks/activity-track.sh +56 -0
  6. package/hooks/codex-workstream.sh +44 -0
  7. package/hooks/gemini-workstream.sh +44 -0
  8. package/hooks/workstream-inject.sh +20 -0
  9. package/lib/activity.js +283 -0
  10. package/lib/apply.js +344 -0
  11. package/lib/cli.js +267 -0
  12. package/lib/config.js +171 -0
  13. package/lib/constants.js +55 -0
  14. package/lib/env.js +114 -0
  15. package/lib/index.js +47 -0
  16. package/lib/init.js +122 -0
  17. package/lib/mcps.js +139 -0
  18. package/lib/memory.js +201 -0
  19. package/lib/projects.js +138 -0
  20. package/lib/registry.js +83 -0
  21. package/lib/utils.js +129 -0
  22. package/lib/workstreams.js +652 -0
  23. package/package.json +80 -0
  24. package/scripts/capture-screenshots.js +142 -0
  25. package/scripts/postinstall.js +122 -0
  26. package/scripts/release.sh +71 -0
  27. package/scripts/sync-version.js +77 -0
  28. package/scripts/tauri-prepare.js +328 -0
  29. package/shared/mcp-registry.json +76 -0
  30. package/ui/dist/assets/index-DbZ3_HBD.js +3204 -0
  31. package/ui/dist/assets/index-DjLdm3Mr.css +32 -0
  32. package/ui/dist/icons/icon-192.svg +16 -0
  33. package/ui/dist/icons/icon-512.svg +16 -0
  34. package/ui/dist/index.html +39 -0
  35. package/ui/dist/manifest.json +25 -0
  36. package/ui/dist/sw.js +24 -0
  37. package/ui/dist/tutorial/claude-settings.png +0 -0
  38. package/ui/dist/tutorial/header.png +0 -0
  39. package/ui/dist/tutorial/mcp-registry.png +0 -0
  40. package/ui/dist/tutorial/memory-view.png +0 -0
  41. package/ui/dist/tutorial/permissions.png +0 -0
  42. package/ui/dist/tutorial/plugins-view.png +0 -0
  43. package/ui/dist/tutorial/project-explorer.png +0 -0
  44. package/ui/dist/tutorial/projects-view.png +0 -0
  45. package/ui/dist/tutorial/sidebar.png +0 -0
  46. package/ui/dist/tutorial/tutorial-view.png +0 -0
  47. package/ui/dist/tutorial/workstreams-view.png +0 -0
  48. package/ui/routes/activity.js +58 -0
  49. package/ui/routes/commands.js +74 -0
  50. package/ui/routes/configs.js +329 -0
  51. package/ui/routes/env.js +40 -0
  52. package/ui/routes/file-explorer.js +668 -0
  53. package/ui/routes/index.js +41 -0
  54. package/ui/routes/mcp-discovery.js +235 -0
  55. package/ui/routes/memory.js +385 -0
  56. package/ui/routes/package.json +3 -0
  57. package/ui/routes/plugins.js +466 -0
  58. package/ui/routes/projects.js +198 -0
  59. package/ui/routes/registry.js +30 -0
  60. package/ui/routes/rules.js +74 -0
  61. package/ui/routes/search.js +125 -0
  62. package/ui/routes/settings.js +381 -0
  63. package/ui/routes/subprojects.js +208 -0
  64. package/ui/routes/tool-sync.js +127 -0
  65. package/ui/routes/updates.js +339 -0
  66. package/ui/routes/workstreams.js +224 -0
  67. package/ui/server.cjs +773 -0
  68. 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;