@becrafter/prompt-manager 0.1.15 → 0.1.16
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.
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@becrafter/prompt-desktop",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@becrafter/prompt-desktop",
|
|
9
|
-
"version": "0.1.
|
|
9
|
+
"version": "0.1.16",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@becrafter/prompt-manager-core": "file:../../packages/server",
|
|
12
12
|
"@modelcontextprotocol/sdk": "^1.20.2",
|
package/app/desktop/package.json
CHANGED
package/env.example
CHANGED
package/package.json
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"dev": "node --watch ./server.js",
|
|
11
11
|
"dev:clean": "node ./dev-server.js",
|
|
12
12
|
"fix:pty": "npm rebuild node-pty",
|
|
13
|
+
"postinstall": "npm run fix:pty",
|
|
13
14
|
"start": "node ./server.js",
|
|
14
15
|
"example": "node --experimental-specifier-resolution=node ./example.js",
|
|
15
16
|
"test": "vitest run tests/unit",
|
|
@@ -52,6 +53,7 @@
|
|
|
52
53
|
"http-proxy-middleware": "^3.0.5",
|
|
53
54
|
"js-yaml": "^4.1.0",
|
|
54
55
|
"multer": "^2.0.2",
|
|
56
|
+
"node-pty": "^1.0.0",
|
|
55
57
|
"ws": "^8.18.0",
|
|
56
58
|
"yaml": "^2.4.1",
|
|
57
59
|
"zod": "^3.23.8"
|
|
@@ -69,7 +69,7 @@ class TerminalSession {
|
|
|
69
69
|
case 'win32':
|
|
70
70
|
return process.env.COMSPEC || 'cmd.exe';
|
|
71
71
|
case 'darwin':
|
|
72
|
-
return process.env.SHELL || '/bin/
|
|
72
|
+
return process.env.SHELL || '/bin/zsh';
|
|
73
73
|
case 'linux':
|
|
74
74
|
return process.env.SHELL || '/bin/bash';
|
|
75
75
|
default:
|
|
@@ -83,15 +83,34 @@ class TerminalSession {
|
|
|
83
83
|
setupPtyEvents() {
|
|
84
84
|
if (!this.pty) return;
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
this.
|
|
89
|
-
|
|
86
|
+
// 对于正常的PTY进程
|
|
87
|
+
if (!this.pty.isFallback) {
|
|
88
|
+
this.pty.on('data', (data) => {
|
|
89
|
+
this.lastActivity = new Date();
|
|
90
|
+
this.emit('data', data);
|
|
91
|
+
});
|
|
90
92
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
this.pty.on('exit', (exitCode, signal) => {
|
|
94
|
+
this.isActive = false;
|
|
95
|
+
this.emit('exit', { exitCode, signal });
|
|
96
|
+
});
|
|
97
|
+
} else {
|
|
98
|
+
// 对于fallback PTY进程(child_process.spawn)
|
|
99
|
+
this.pty.process.stdout?.on('data', (data) => {
|
|
100
|
+
this.lastActivity = new Date();
|
|
101
|
+
this.emit('data', data);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
this.pty.process.stderr?.on('data', (data) => {
|
|
105
|
+
this.lastActivity = new Date();
|
|
106
|
+
this.emit('data', data);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
this.pty.process.on('exit', (exitCode, signal) => {
|
|
110
|
+
this.isActive = false;
|
|
111
|
+
this.emit('exit', { exitCode, signal });
|
|
112
|
+
});
|
|
113
|
+
}
|
|
95
114
|
}
|
|
96
115
|
|
|
97
116
|
/**
|
|
@@ -101,7 +120,14 @@ class TerminalSession {
|
|
|
101
120
|
if (!this.isActive || !this.pty) {
|
|
102
121
|
throw new Error('Terminal session is not active');
|
|
103
122
|
}
|
|
104
|
-
|
|
123
|
+
|
|
124
|
+
if (this.pty.isFallback) {
|
|
125
|
+
// fallback PTY使用child_process
|
|
126
|
+
this.pty.process.stdin?.write(data);
|
|
127
|
+
} else {
|
|
128
|
+
// 正常PTY
|
|
129
|
+
this.pty.write(data);
|
|
130
|
+
}
|
|
105
131
|
this.lastActivity = new Date();
|
|
106
132
|
}
|
|
107
133
|
|
|
@@ -112,7 +138,14 @@ class TerminalSession {
|
|
|
112
138
|
if (!this.isActive || !this.pty) {
|
|
113
139
|
throw new Error('Terminal session is not active');
|
|
114
140
|
}
|
|
115
|
-
|
|
141
|
+
|
|
142
|
+
if (this.pty.isFallback) {
|
|
143
|
+
// fallback PTY不支持resize,记录日志
|
|
144
|
+
logger.debug(`Fallback PTY resize requested: ${cols}x${rows} (not supported)`);
|
|
145
|
+
} else {
|
|
146
|
+
// 正常PTY支持resize
|
|
147
|
+
this.pty.resize(cols, rows);
|
|
148
|
+
}
|
|
116
149
|
this.size = { cols, rows };
|
|
117
150
|
}
|
|
118
151
|
|
|
@@ -121,7 +154,13 @@ class TerminalSession {
|
|
|
121
154
|
*/
|
|
122
155
|
terminate() {
|
|
123
156
|
if (this.pty) {
|
|
124
|
-
this.pty.
|
|
157
|
+
if (this.pty.isFallback) {
|
|
158
|
+
// fallback PTY使用child_process
|
|
159
|
+
this.pty.process.kill();
|
|
160
|
+
} else {
|
|
161
|
+
// 正常PTY
|
|
162
|
+
this.pty.kill();
|
|
163
|
+
}
|
|
125
164
|
}
|
|
126
165
|
this.isActive = false;
|
|
127
166
|
}
|
|
@@ -255,6 +294,17 @@ export class TerminalService {
|
|
|
255
294
|
const shells = this.getShellCandidates(options.shell);
|
|
256
295
|
let lastError = null;
|
|
257
296
|
|
|
297
|
+
// 在macOS上确保PATH包含常用目录
|
|
298
|
+
if (process.platform === 'darwin') {
|
|
299
|
+
const defaultPath = '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin';
|
|
300
|
+
if (!env.PATH || env.PATH === '') {
|
|
301
|
+
env.PATH = defaultPath;
|
|
302
|
+
} else if (!env.PATH.includes('/usr/local/bin')) {
|
|
303
|
+
env.PATH = `${env.PATH}:${defaultPath}`;
|
|
304
|
+
}
|
|
305
|
+
logger.debug(`macOS PATH configured: ${env.PATH}`);
|
|
306
|
+
}
|
|
307
|
+
|
|
258
308
|
for (const candidate of shells) {
|
|
259
309
|
if (!candidate) continue;
|
|
260
310
|
const resolvedShell = this.resolveShellPath(candidate);
|
|
@@ -267,22 +317,96 @@ export class TerminalService {
|
|
|
267
317
|
logger.debug(`Creating PTY with shell: ${resolvedShell}, args: ${args.join(' ')}, cwd: ${cwd}`);
|
|
268
318
|
|
|
269
319
|
try {
|
|
270
|
-
|
|
320
|
+
const ptyProcess = pty.default.spawn(resolvedShell, args, {
|
|
271
321
|
name: 'xterm-color',
|
|
272
322
|
cols: options.size.cols,
|
|
273
323
|
rows: options.size.rows,
|
|
274
324
|
cwd: cwd,
|
|
275
325
|
env: env
|
|
276
326
|
});
|
|
327
|
+
|
|
328
|
+
// 添加PTY进程的事件监听,用于调试
|
|
329
|
+
ptyProcess.on('data', (data) => {
|
|
330
|
+
logger.debug(`PTY data received: ${data.length} bytes`);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
ptyProcess.on('exit', (code, signal) => {
|
|
334
|
+
logger.debug(`PTY process exited: code=${code}, signal=${signal}`);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
return ptyProcess;
|
|
277
338
|
} catch (error) {
|
|
278
339
|
lastError = error;
|
|
279
340
|
logger.warn(`Failed to spawn shell ${resolvedShell}: ${error.message}`);
|
|
341
|
+
|
|
342
|
+
// 如果是posix_spawnp失败,尝试备用方案
|
|
343
|
+
if (error.message.includes('posix_spawnp')) {
|
|
344
|
+
logger.warn('posix_spawnp failed, trying alternative approach...');
|
|
345
|
+
try {
|
|
346
|
+
// 尝试使用child_process.spawn作为备用方案
|
|
347
|
+
const { spawn } = await import('child_process');
|
|
348
|
+
const child = spawn(resolvedShell, args, {
|
|
349
|
+
cwd: cwd,
|
|
350
|
+
env: env,
|
|
351
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
352
|
+
shell: false
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// 包装child_process.spawn的结果以兼容PTY接口
|
|
356
|
+
return this.createFallbackPtyProcess(child, options);
|
|
357
|
+
} catch (fallbackError) {
|
|
358
|
+
logger.warn(`Fallback spawn also failed: ${fallbackError.message}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
280
361
|
}
|
|
281
362
|
}
|
|
282
363
|
|
|
283
364
|
throw lastError || new Error('Unable to create PTY session: no suitable shell found');
|
|
284
365
|
}
|
|
285
366
|
|
|
367
|
+
/**
|
|
368
|
+
* 创建备用PTY进程(使用child_process.spawn)
|
|
369
|
+
*/
|
|
370
|
+
createFallbackPtyProcess(childProcess, options) {
|
|
371
|
+
// 创建一个兼容PTY接口的对象
|
|
372
|
+
const fallbackPty = {
|
|
373
|
+
pid: childProcess.pid,
|
|
374
|
+
cols: options.size.cols,
|
|
375
|
+
rows: options.size.rows,
|
|
376
|
+
process: childProcess,
|
|
377
|
+
isFallback: true,
|
|
378
|
+
|
|
379
|
+
write(data) {
|
|
380
|
+
if (childProcess.stdin) {
|
|
381
|
+
childProcess.stdin.write(data);
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
|
|
385
|
+
resize(cols, rows) {
|
|
386
|
+
this.cols = cols;
|
|
387
|
+
this.rows = rows;
|
|
388
|
+
// child_process不支持resize,记录日志
|
|
389
|
+
logger.debug(`Fallback PTY resize requested: ${cols}x${rows} (not supported)`);
|
|
390
|
+
},
|
|
391
|
+
|
|
392
|
+
kill(signal = 'SIGTERM') {
|
|
393
|
+
childProcess.kill(signal);
|
|
394
|
+
},
|
|
395
|
+
|
|
396
|
+
on(event, callback) {
|
|
397
|
+
if (event === 'data') {
|
|
398
|
+
childProcess.stdout?.on('data', callback);
|
|
399
|
+
childProcess.stderr?.on('data', callback);
|
|
400
|
+
} else if (event === 'exit') {
|
|
401
|
+
childProcess.on('exit', callback);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
logger.info('Created fallback PTY process (limited functionality)');
|
|
407
|
+
return fallbackPty;
|
|
408
|
+
}
|
|
409
|
+
|
|
286
410
|
/**
|
|
287
411
|
* 获取平台对应的默认Shell
|
|
288
412
|
*/
|
|
@@ -292,7 +416,7 @@ export class TerminalService {
|
|
|
292
416
|
return process.env.COMSPEC || 'cmd.exe';
|
|
293
417
|
case 'darwin':
|
|
294
418
|
// 在 macOS 上优先使用用户的 SHELL 环境变量
|
|
295
|
-
return process.env.SHELL || '/bin/zsh'
|
|
419
|
+
return process.env.SHELL || '/bin/zsh';
|
|
296
420
|
case 'linux':
|
|
297
421
|
return process.env.SHELL || '/bin/bash';
|
|
298
422
|
default:
|
|
@@ -121,7 +121,7 @@ export class Config {
|
|
|
121
121
|
|
|
122
122
|
// 其他配置
|
|
123
123
|
this.serverName = process.env.MCP_SERVER_NAME || 'prompt-manager';
|
|
124
|
-
this.serverVersion = process.env.MCP_SERVER_VERSION || '0.1.
|
|
124
|
+
this.serverVersion = process.env.MCP_SERVER_VERSION || '0.1.16';
|
|
125
125
|
this.logLevel = process.env.LOG_LEVEL || 'info';
|
|
126
126
|
this.maxPrompts = parseInt(process.env.MAX_PROMPTS) || 1000;
|
|
127
127
|
this.recursiveScan = process.env.RECURSIVE_SCAN !== 'false'; // 默认启用递归扫描
|