@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.15",
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.15",
9
+ "version": "0.1.16",
10
10
  "dependencies": {
11
11
  "@becrafter/prompt-manager-core": "file:../../packages/server",
12
12
  "@modelcontextprotocol/sdk": "^1.20.2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@becrafter/prompt-desktop",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Menu bar desktop wrapper for @becrafter/prompt-manager",
5
5
  "author": "BeCrafter",
6
6
  "homepage": "https://github.com/BeCrafter/prompt-manager",
package/env.example CHANGED
@@ -7,7 +7,7 @@ PROMPTS_DIR=$HOME/.prompt-manager/prompts
7
7
 
8
8
  # MCP服务器配置
9
9
  MCP_SERVER_NAME=prompt-manager
10
- MCP_SERVER_VERSION=0.1.15
10
+ MCP_SERVER_VERSION=0.1.16
11
11
 
12
12
  # 日志级别 (error, warn, info, debug)
13
13
  LOG_LEVEL=info
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@becrafter/prompt-manager",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Remote MCP Server for managing prompts",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -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/bash';
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
- this.pty.on('data', (data) => {
87
- this.lastActivity = new Date();
88
- this.emit('data', data);
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
- this.pty.on('exit', (exitCode, signal) => {
92
- this.isActive = false;
93
- this.emit('exit', { exitCode, signal });
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
- this.pty.write(data);
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
- this.pty.resize(cols, rows);
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.kill();
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
- return pty.default.spawn(resolvedShell, args, {
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' || '/bin/bash';
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.15';
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'; // 默认启用递归扫描