@becrafter/prompt-manager 0.1.16 → 0.1.18

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.16",
3
+ "version": "0.1.18",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@becrafter/prompt-desktop",
9
- "version": "0.1.16",
9
+ "version": "0.1.18",
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.16",
3
+ "version": "0.1.18",
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.16
10
+ MCP_SERVER_VERSION=0.1.18
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.16",
3
+ "version": "0.1.18",
4
4
  "description": "Remote MCP Server for managing prompts",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -104,8 +104,8 @@ async function sendIndexHtml(req, res) {
104
104
  // 从 adminUiRoot 中提取 asar 文件路径和相对路径
105
105
  const asarPathMatch = adminUiRoot.match(/^(.*?\.asar)(\/.*)?$/);
106
106
  const asarFilePath = asarPathMatch ? asarPathMatch[1] : adminUiRoot.replace(/\/.*$/, '.asar');
107
- const relativePathInAsar = asarPathMatch && asarPathMatch[2] ? asarPathMatch[2].substring(1) : 'packages/web';
108
- const indexPath = path.posix.join(relativePathInAsar, 'admin.html');
107
+ const relativePathInAsar = asarPathMatch && asarPathMatch[2] ? asarPathMatch[2].substring(1) : 'web';
108
+ const indexPath = path.posix.join(relativePathInAsar, 'index.html');
109
109
 
110
110
  // 检查文件是否存在
111
111
  const stat = asar.statFile(asarFilePath, indexPath);
@@ -121,17 +121,7 @@ async function sendIndexHtml(req, res) {
121
121
  res.status(500).send('Internal Server Error');
122
122
  }
123
123
  } else {
124
- // 优先查找 index.html,如果不存在则使用 admin.html
125
- const indexPath = path.join(adminUiRoot, 'index.html');
126
- const adminPath = path.join(adminUiRoot, 'admin.html');
127
-
128
- if (fs.existsSync(indexPath)) {
129
- res.sendFile(indexPath);
130
- } else if (fs.existsSync(adminPath)) {
131
- res.sendFile(adminPath);
132
- } else {
133
- res.status(404).send('Admin UI not found');
134
- }
124
+ res.sendFile(path.join(adminUiRoot, 'index.html'));
135
125
  }
136
126
  }
137
127
 
@@ -7,7 +7,6 @@
7
7
 
8
8
  import { spawn } from 'child_process';
9
9
  import { randomUUID } from 'crypto';
10
- import fs from 'fs';
11
10
  import { logger } from '../utils/logger.js';
12
11
  import path from 'path';
13
12
  import os from 'os';
@@ -69,7 +68,7 @@ class TerminalSession {
69
68
  case 'win32':
70
69
  return process.env.COMSPEC || 'cmd.exe';
71
70
  case 'darwin':
72
- return process.env.SHELL || '/bin/zsh';
71
+ return process.env.SHELL || '/bin/bash';
73
72
  case 'linux':
74
73
  return process.env.SHELL || '/bin/bash';
75
74
  default:
@@ -83,34 +82,15 @@ class TerminalSession {
83
82
  setupPtyEvents() {
84
83
  if (!this.pty) return;
85
84
 
86
- // 对于正常的PTY进程
87
- if (!this.pty.isFallback) {
88
- this.pty.on('data', (data) => {
89
- this.lastActivity = new Date();
90
- this.emit('data', data);
91
- });
92
-
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
- });
85
+ this.pty.on('data', (data) => {
86
+ this.lastActivity = new Date();
87
+ this.emit('data', data);
88
+ });
108
89
 
109
- this.pty.process.on('exit', (exitCode, signal) => {
110
- this.isActive = false;
111
- this.emit('exit', { exitCode, signal });
112
- });
113
- }
90
+ this.pty.on('exit', (exitCode, signal) => {
91
+ this.isActive = false;
92
+ this.emit('exit', { exitCode, signal });
93
+ });
114
94
  }
115
95
 
116
96
  /**
@@ -120,14 +100,7 @@ class TerminalSession {
120
100
  if (!this.isActive || !this.pty) {
121
101
  throw new Error('Terminal session is not active');
122
102
  }
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
- }
103
+ this.pty.write(data);
131
104
  this.lastActivity = new Date();
132
105
  }
133
106
 
@@ -138,14 +111,7 @@ class TerminalSession {
138
111
  if (!this.isActive || !this.pty) {
139
112
  throw new Error('Terminal session is not active');
140
113
  }
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
- }
114
+ this.pty.resize(cols, rows);
149
115
  this.size = { cols, rows };
150
116
  }
151
117
 
@@ -154,13 +120,7 @@ class TerminalSession {
154
120
  */
155
121
  terminate() {
156
122
  if (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
- }
123
+ this.pty.kill();
164
124
  }
165
125
  this.isActive = false;
166
126
  }
@@ -289,122 +249,20 @@ export class TerminalService {
289
249
  * 创建PTY进程
290
250
  */
291
251
  async createPtyProcess(options) {
252
+ const shell = options.shell || this.getDefaultShellForPlatform();
253
+ const args = this.getShellArgs(shell);
292
254
  const cwd = options.workingDirectory || os.homedir();
293
255
  const env = { ...process.env, ...options.environment };
294
- const shells = this.getShellCandidates(options.shell);
295
- let lastError = null;
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
-
308
- for (const candidate of shells) {
309
- if (!candidate) continue;
310
- const resolvedShell = this.resolveShellPath(candidate);
311
- if (!resolvedShell) {
312
- logger.debug(`Shell not found on system: ${candidate}`);
313
- continue;
314
- }
315
-
316
- const args = this.getShellArgs(resolvedShell);
317
- logger.debug(`Creating PTY with shell: ${resolvedShell}, args: ${args.join(' ')}, cwd: ${cwd}`);
318
256
 
319
- try {
320
- const ptyProcess = pty.default.spawn(resolvedShell, args, {
321
- name: 'xterm-color',
322
- cols: options.size.cols,
323
- rows: options.size.rows,
324
- cwd: cwd,
325
- env: env
326
- });
257
+ logger.debug(`Creating PTY with shell: ${shell}, args: ${args.join(' ')}, cwd: ${cwd}`);
327
258
 
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;
338
- } catch (error) {
339
- lastError = error;
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
- }
361
- }
362
- }
363
-
364
- throw lastError || new Error('Unable to create PTY session: no suitable shell found');
365
- }
366
-
367
- /**
368
- * 创建备用PTY进程(使用child_process.spawn)
369
- */
370
- createFallbackPtyProcess(childProcess, options) {
371
- // 创建一个兼容PTY接口的对象
372
- const fallbackPty = {
373
- pid: childProcess.pid,
259
+ return pty.default.spawn(shell, args, {
260
+ name: 'xterm-color',
374
261
  cols: options.size.cols,
375
262
  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;
263
+ cwd: cwd,
264
+ env: env
265
+ });
408
266
  }
409
267
 
410
268
  /**
@@ -415,8 +273,7 @@ export class TerminalService {
415
273
  case 'win32':
416
274
  return process.env.COMSPEC || 'cmd.exe';
417
275
  case 'darwin':
418
- // macOS 上优先使用用户的 SHELL 环境变量
419
- return process.env.SHELL || '/bin/zsh';
276
+ return process.env.SHELL || '/bin/bash';
420
277
  case 'linux':
421
278
  return process.env.SHELL || '/bin/bash';
422
279
  default:
@@ -434,63 +291,9 @@ export class TerminalService {
434
291
  }
435
292
  return ['/c'];
436
293
  }
437
-
438
- // 某些精简 shell(如 /bin/sh)不支持 -l
439
- if (shell.endsWith('/sh')) {
440
- return ['-i'];
441
- }
442
-
443
294
  return ['-l'];
444
295
  }
445
296
 
446
- /**
447
- * 获取 shell 候选列表(按优先级)
448
- */
449
- getShellCandidates(preferredShell) {
450
- const candidates = [];
451
-
452
- if (preferredShell) candidates.push(preferredShell);
453
- if (process.env.SHELL) candidates.push(process.env.SHELL);
454
-
455
- if (process.platform === 'darwin') {
456
- candidates.push('/bin/zsh', '/bin/bash', '/bin/sh');
457
- } else if (process.platform === 'linux') {
458
- candidates.push('/bin/bash', '/bin/sh');
459
- } else if (process.platform === 'win32') {
460
- candidates.push(process.env.COMSPEC || 'cmd.exe');
461
- } else {
462
- candidates.push('/bin/sh');
463
- }
464
-
465
- return [...new Set(candidates)];
466
- }
467
-
468
- /**
469
- * 确保 shell 路径在当前系统存在
470
- */
471
- resolveShellPath(shellPath) {
472
- // 绝对路径直接检查
473
- if (shellPath.startsWith('/')) {
474
- return fs.existsSync(shellPath) ? shellPath : null;
475
- }
476
-
477
- // Windows 可执行文件
478
- if (process.platform === 'win32') {
479
- return shellPath;
480
- }
481
-
482
- // 如果是相对路径,尝试在常见目录查找
483
- const searchPaths = ['/bin', '/usr/bin', '/usr/local/bin'];
484
- for (const base of searchPaths) {
485
- const fullPath = path.join(base, shellPath);
486
- if (fs.existsSync(fullPath)) {
487
- return fullPath;
488
- }
489
- }
490
-
491
- return null;
492
- }
493
-
494
297
  /**
495
298
  * 获取会话
496
299
  */
@@ -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.16';
124
+ this.serverVersion = process.env.MCP_SERVER_VERSION || '0.1.18';
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'; // 默认启用递归扫描