sloth-d2c-mcp 1.0.4-beta83 → 1.0.4-beta85

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/cli/run.js CHANGED
@@ -113,6 +113,76 @@ if (args[0] === 'config') {
113
113
 
114
114
  console.log(`[sloth] 已在后台启动,PID: ${child.pid}`);
115
115
  process.exit(0);
116
+ } else if (args[0] === 'stop') {
117
+ // stop 命令:停止监听 3100/3101 端口的 sloth 进程
118
+ const { execSync } = await import('node:child_process');
119
+ const os = await import('node:os');
120
+
121
+ const ports = [3100, 3101];
122
+ const pidsToKill = new Set();
123
+
124
+ for (const port of ports) {
125
+ try {
126
+ let output = '';
127
+ if (os.platform() === 'win32') {
128
+ // Windows: netstat -ano | findstr :PORT
129
+ output = execSync(`netstat -ano | findstr :${port}`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
130
+ const lines = output.trim().split('\n');
131
+ for (const line of lines) {
132
+ const match = line.match(/LISTENING\s+(\d+)/);
133
+ if (match) {
134
+ pidsToKill.add(match[1]);
135
+ }
136
+ }
137
+ } else {
138
+ // macOS/Linux: lsof -i :PORT
139
+ output = execSync(`lsof -i :${port} -t`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
140
+ const pids = output.trim().split('\n').filter(Boolean);
141
+ pids.forEach(pid => pidsToKill.add(pid.trim()));
142
+ }
143
+ } catch {
144
+ // 端口未被占用,忽略错误
145
+ }
146
+ }
147
+
148
+ if (pidsToKill.size === 0) {
149
+ console.log('[sloth] 未找到监听 3100/3101 端口的进程');
150
+ process.exit(0);
151
+ }
152
+
153
+ // 验证进程是否是 sloth 相关进程
154
+ let killedCount = 0;
155
+ for (const pid of pidsToKill) {
156
+ try {
157
+ let cmdline = '';
158
+ if (os.platform() === 'win32') {
159
+ cmdline = execSync(`wmic process where processid=${pid} get commandline`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
160
+ } else {
161
+ cmdline = execSync(`ps -p ${pid} -o command=`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
162
+ }
163
+
164
+ // 检查是否是 sloth 进程
165
+ const isSlothProcess = cmdline.includes('sloth') || cmdline.includes('d2c-mcp');
166
+
167
+ if (isSlothProcess) {
168
+ process.kill(Number(pid), 'SIGTERM');
169
+ console.log(`[sloth] 已停止进程 PID: ${pid}`);
170
+ killedCount++;
171
+ } else {
172
+ console.log(`[sloth] 跳过非 sloth 进程 PID: ${pid} (${cmdline.trim().slice(0, 50)}...)`);
173
+ }
174
+ } catch (e) {
175
+ // 进程可能已经退出
176
+ console.warn(`[sloth] 无法停止进程 PID: ${pid}`, e.message);
177
+ }
178
+ }
179
+
180
+ if (killedCount === 0) {
181
+ console.log('[sloth] 未找到正在运行的 sloth 进程');
182
+ } else {
183
+ console.log(`[sloth] 共停止 ${killedCount} 个进程`);
184
+ }
185
+ process.exit(0);
116
186
  } else {
117
187
  // 设置环境变量为CLI模式
118
188
  process.env.NODE_ENV = "cli";
@@ -11,7 +11,7 @@ import { loadConfig, startHttpServer, stopHttpServer, generateComponentId, stopS
11
11
  import { FileManager } from './utils/file-manager.js';
12
12
  import { updateImageMapIfNeeded } from './utils/update.js';
13
13
  import { Logger } from './utils/logger.js';
14
- import { getAvailablePort, saveImageFile, replaceImageSrc } from './utils/utils.js';
14
+ import { getAvailablePort, saveImageFile, replaceImageSrc, formatListRoots } from './utils/utils.js';
15
15
  import { processSampling, buildNestingStructure } from './core/sampling.js';
16
16
  import { buildComponentMappingPrompt, buildFullUpdatePromptForAI, buildPlaceholderPrompt } from './core/prompt-builder.js';
17
17
  import { detectClientApiSupport, clearCapabilitiesCache } from './utils/client-capabilities.js';
@@ -99,7 +99,8 @@ mcpServer.tool('d2c_figma', 'Convert Figma Design File to Code', {
99
99
  try {
100
100
  const rootRes = await mcpServer.server.listRoots();
101
101
  Logger.log('获取根目录:', rootRes);
102
- root = rootRes.roots[0]?.uri?.slice(7) || './';
102
+ root = formatListRoots(rootRes);
103
+ Logger.log('标准化根目录:', root);
103
104
  // 设置 fileManager 的工作目录根路径
104
105
  fileManager.setWorkspaceRoot(root);
105
106
  }
@@ -530,7 +531,8 @@ mcpServer.tool('mark_components', 'Mark and save components to project component
530
531
  try {
531
532
  const rootRes = await mcpServer.server.listRoots();
532
533
  Logger.log('获取根目录:', rootRes);
533
- root = rootRes.roots[0]?.uri?.slice(7) || './';
534
+ root = formatListRoots(rootRes);
535
+ Logger.log('标准化根目录:', root);
534
536
  // 设置 fileManager 的工作目录根路径
535
537
  fileManager.setWorkspaceRoot(root);
536
538
  }
@@ -3,6 +3,7 @@ import { execSync } from 'child_process';
3
3
  import axios from 'axios';
4
4
  import fs from 'fs';
5
5
  import path from 'path';
6
+ import { fileURLToPath } from 'url';
6
7
  /**
7
8
  * 获取可用的端口号,从指定端口开始寻找
8
9
  * @param startPort 起始端口号,默认3100
@@ -163,3 +164,15 @@ export const resetNodeListPosition = (nodeList) => {
163
164
  return node;
164
165
  });
165
166
  };
167
+ export const formatListRoots = (rootRes) => {
168
+ let root = rootRes.roots[0]?.uri;
169
+ if (root) {
170
+ // 兼容window下roots返回的路径是url编码的
171
+ root = decodeURIComponent(root);
172
+ root = fileURLToPath(root);
173
+ }
174
+ else {
175
+ root = './';
176
+ }
177
+ return root;
178
+ };
@@ -1,5 +1,5 @@
1
1
  {
2
- "buildTime": "2025-12-24T13:36:17.450Z",
2
+ "buildTime": "2025-12-26T06:52:56.550Z",
3
3
  "mode": "build",
4
4
  "pages": {
5
5
  "main": {