tt-help-cli-ycl 1.4.66 → 1.4.68

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tt-help-cli-ycl",
3
- "version": "1.4.66",
3
+ "version": "1.4.68",
4
4
  "description": "TikTok user & video data scraper - extract ttSeller, verified, locationCreated from HTML source",
5
5
  "type": "module",
6
6
  "bin": {
@@ -3562,7 +3562,17 @@ function renderOfflineCard(userId, cmds) {
3562
3562
  "div",
3563
3563
  "display:flex;gap:10px;align-items:center",
3564
3564
  styled("span", "color:#f87171", "● 离线") +
3565
- styled("span", "color:#555;font-size:10px", "—"),
3565
+ styled("span", "color:#555;font-size:10px", "—") +
3566
+ tag(
3567
+ "button",
3568
+ {
3569
+ onclick: "wdDeleteClient('" + esc(userId) + "')",
3570
+ style:
3571
+ "padding:2px 8px;font-size:10px;background:#991b1b;color:#fff;border:none;border-radius:3px;cursor:pointer",
3572
+ title: "删除此客户端配置",
3573
+ },
3574
+ "删除",
3575
+ ),
3566
3576
  ),
3567
3577
  ) +
3568
3578
  styled(
@@ -3623,7 +3633,19 @@ function renderClientCard(c, clientCommands) {
3623
3633
  "display:flex;gap:10px;align-items:center",
3624
3634
  styled("span", "color:#888;font-size:11px", c.ip) +
3625
3635
  onlineBadge +
3626
- styled("span", "color:#666;font-size:10px", lastSeen),
3636
+ styled("span", "color:#666;font-size:10px", lastSeen) +
3637
+ (!c.online && userId
3638
+ ? tag(
3639
+ "button",
3640
+ {
3641
+ onclick: "wdDeleteClient('" + esc(userId) + "')",
3642
+ style:
3643
+ "padding:2px 8px;font-size:10px;background:#991b1b;color:#fff;border:none;border-radius:3px;cursor:pointer;margin-left:6px",
3644
+ title: "删除此客户端配置",
3645
+ },
3646
+ "删除",
3647
+ )
3648
+ : ""),
3627
3649
  ),
3628
3650
  );
3629
3651
 
@@ -3889,3 +3911,15 @@ async function wdSaveClientCmds(userId, commands) {
3889
3911
  alert("保存失败: " + e.message);
3890
3912
  }
3891
3913
  }
3914
+
3915
+ function wdDeleteClient(userId) {
3916
+ if (
3917
+ !confirm(
3918
+ "确定删除 " +
3919
+ userId +
3920
+ " 的所有命令配置?\n\n删除后该客户端将不再出现在列表中。",
3921
+ )
3922
+ )
3923
+ return;
3924
+ wdSaveClientCmds(userId, []);
3925
+ }
@@ -44,19 +44,6 @@ function splitCommand(cmdLine) {
44
44
  return parts;
45
45
  }
46
46
 
47
- // Windows: 从 cmd.exe 往下找真正的子进程 PID(跳过 conhost)
48
- function getChildPid(parentPid) {
49
- try {
50
- const out = execSync(
51
- `powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter 'ParentProcessId=${parentPid}' | Where-Object { $_.Name -ne 'conhost.exe' } | Select-Object -First 1 -ExpandProperty ProcessId"`,
52
- { encoding: "utf-8", timeout: 3000, stdio: ["ignore", "pipe", "ignore"] },
53
- ).trim();
54
- return parseInt(out, 10) || 0;
55
- } catch {
56
- return 0;
57
- }
58
- }
59
-
60
47
  function getProcessStats(pid) {
61
48
  try {
62
49
  const cmd = IS_WIN
@@ -119,15 +106,15 @@ export class ProcessManager extends EventEmitter {
119
106
  let child;
120
107
  const startTime = Date.now();
121
108
  try {
122
- // 拆分为 program + args;Windows .cmd 需 shell,用完整命令行
109
+ // 拆分为 program + args(引号感知)
123
110
  if (args.length === 0) {
124
111
  const parts = splitCommand(command);
125
112
  command = parts[0] || command;
126
113
  args = parts.slice(1);
127
114
  }
128
- const fullCmd = [command, ...args].join(" ");
115
+ // Windows .cmd 文件必须 shell:true,macOS/Linux 直接 spawn
129
116
  child = IS_WIN
130
- ? spawn(fullCmd, {
117
+ ? spawn(command, args, {
131
118
  stdio: ["ignore", "pipe", "pipe"],
132
119
  detached: false,
133
120
  shell: true,
@@ -136,19 +123,6 @@ export class ProcessManager extends EventEmitter {
136
123
  stdio: ["ignore", "pipe", "pipe"],
137
124
  detached: false,
138
125
  });
139
-
140
- // Windows: cmd.exe 不是真实进程,延迟获取子进程 PID
141
- if (IS_WIN) {
142
- setTimeout(() => {
143
- const realPid = getChildPid(child.pid);
144
- if (realPid > 0) {
145
- const info = this.processes.get(id);
146
- if (info && info.child === child) {
147
- info._realPid = realPid;
148
- }
149
- }
150
- }, 2000);
151
- }
152
126
  } catch (e) {
153
127
  console.error(`[watchdog] 启动命令 ${id} 失败: ${e.message}`);
154
128
  this.processes.set(id, {
@@ -236,16 +210,23 @@ export class ProcessManager extends EventEmitter {
236
210
 
237
211
  if (info.child) {
238
212
  try {
239
- // 尝试优雅终止
240
- info.child.kill("SIGTERM");
241
- // 2 秒后强制 kill
242
- setTimeout(() => {
243
- try {
244
- if (info.child && info.child.exitCode === null) {
245
- info.child.kill("SIGKILL");
246
- }
247
- } catch {}
248
- }, 2000);
213
+ if (IS_WIN) {
214
+ // Windows: shell:true 产生 cmd.exe 中间层,必须杀整个进程树
215
+ execSync(`taskkill /PID ${info.child.pid} /T /F`, {
216
+ stdio: ["ignore", "ignore", "ignore"],
217
+ timeout: 5000,
218
+ });
219
+ } else {
220
+ // macOS/Linux: 优雅终止,2 秒后强制 kill
221
+ info.child.kill("SIGTERM");
222
+ setTimeout(() => {
223
+ try {
224
+ if (info.child && info.child.exitCode === null) {
225
+ info.child.kill("SIGKILL");
226
+ }
227
+ } catch {}
228
+ }, 2000);
229
+ }
249
230
  } catch (e) {
250
231
  console.error(`[watchdog] 停止命令 ${cmdId} 失败: ${e.message}`);
251
232
  }
@@ -262,8 +243,7 @@ export class ProcessManager extends EventEmitter {
262
243
  const result = [];
263
244
  for (const [cmdId, info] of this.processes) {
264
245
  if (info.stopped) continue;
265
- // Windows: 优先用真实子进程 PID(否则拿到的是 cmd.exe 的内存)
266
- const pid = info._realPid || info.child?.pid || 0;
246
+ const pid = info.child?.pid || 0;
267
247
  const stats = pid ? getProcessStats(pid) : null;
268
248
  const uptimeSeconds = Math.round((Date.now() - info.startTime) / 1000);
269
249
 
@@ -370,7 +350,7 @@ export class ProcessManager extends EventEmitter {
370
350
  if (info.stopped || !info.child) continue;
371
351
  const thresholds = info.thresholds || {};
372
352
  const uptimeSeconds = Math.round((now - info.startTime) / 1000);
373
- const pid = info._realPid || info.child.pid;
353
+ const pid = info.child.pid;
374
354
 
375
355
  let reason = "";
376
356
  // 检查运行时长