@lark-apaas/coding-templates 0.1.43-alpha.10 → 0.1.43-alpha.12

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": "@lark-apaas/coding-templates",
3
- "version": "0.1.43-alpha.10",
3
+ "version": "0.1.43-alpha.12",
4
4
  "description": "OpenClaw project templates for mclaw CLI",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -44,7 +44,7 @@
44
44
  "@radix-ui/react-toggle": "^1.1.9",
45
45
  "@radix-ui/react-toggle-group": "^1.1.10",
46
46
  "@radix-ui/react-tooltip": "^1.1.18",
47
- "@lark-apaas/client-toolkit-lite": "1.1.7-alpha.11",
47
+ "@lark-apaas/client-toolkit-lite": "1.1.7-alpha.14",
48
48
  "@formkit/auto-animate": "^0.9.0",
49
49
  "@gsap/react": "^2.1.2",
50
50
  "framer-motion": "^12.38.0",
@@ -80,7 +80,7 @@
80
80
  "@types/react": "^19",
81
81
  "@types/react-dom": "^19",
82
82
  "@lark-apaas/coding-presets": "^1.0.0",
83
- "@lark-apaas/coding-vite-preset": "1.0.7-alpha.8",
83
+ "@lark-apaas/coding-vite-preset": "1.0.7-alpha.10",
84
84
  "concurrently": "^9",
85
85
  "eslint": "^9",
86
86
  "eslint-plugin-react-hooks": "^7",
@@ -11,20 +11,28 @@
11
11
  * - vite → 8001(CLIENT_DEV_PORT 可覆盖)
12
12
  * - mock-health → 3000(占位,老沙箱探针兼容用)
13
13
  *
14
- * Ctrl+C / SIGTERM 时 kill 整个进程组。
14
+ * 进程组与孤儿清理:
15
+ * - 子进程 detached: true → 自己一个 PGID,cleanup 时 process.kill(-pid) 整组带走
16
+ * - 监听 SIGINT/SIGTERM/SIGHUP/uncaughtException 触发 cleanup
17
+ * - 启动前 killOrphansByPort 清理端口残留孤儿(应对沙箱保活重启)
18
+ *
19
+ * 触发重启场景:
20
+ * - `pkill -f "npm run dev"` 杀 npm 进程 → dev.cjs 收 SIGHUP → cleanup
21
+ * - 沙箱保活机制重启 npm run dev → 新 dev.cjs → killOrphansByPort 清理旧 vite/mock-health
15
22
  */
16
23
  'use strict';
17
24
 
18
25
  const fs = require('fs');
19
26
  const path = require('path');
20
27
  const readline = require('readline');
21
- const { spawn } = require('child_process');
28
+ const { spawn, execSync } = require('child_process');
22
29
 
23
30
  const ROOT = path.resolve(__dirname, '..');
24
31
  process.chdir(ROOT);
25
32
 
26
33
  const LOG_DIR = process.env.LOG_DIR || 'logs';
27
34
  const CLIENT_DEV_PORT = process.env.CLIENT_DEV_PORT || '8001';
35
+ const HEALTH_PORT = '3000';
28
36
 
29
37
  fs.mkdirSync(LOG_DIR, { recursive: true });
30
38
 
@@ -37,6 +45,38 @@ function timestamp() {
37
45
  );
38
46
  }
39
47
 
48
+ function log(msg) {
49
+ const line = `[${timestamp()}] [dev] ${msg}\n`;
50
+ try { process.stdout.write(line); } catch {}
51
+ }
52
+
53
+ /**
54
+ * 启动前清理端口占用的孤儿进程(沙箱保活重启时关键):
55
+ * 之前 dev.cjs 被 pkill 杀掉后,子进程的 vite/mock-health 可能没被一起带走,
56
+ * 保活机制重启新 dev.cjs 时发现端口被占,导致 vite/mock-health 起不来。
57
+ */
58
+ function killOrphansByPort(port) {
59
+ try {
60
+ const out = execSync(`lsof -ti:${port}`, { stdio: ['ignore', 'pipe', 'ignore'] })
61
+ .toString()
62
+ .trim();
63
+ if (!out) return [];
64
+ const pids = out.split('\n').filter(Boolean);
65
+ for (const pid of pids) {
66
+ try {
67
+ process.kill(Number(pid), 'SIGKILL');
68
+ log(`killed orphan pid=${pid} on :${port}`);
69
+ } catch {
70
+ // 进程可能已退出
71
+ }
72
+ }
73
+ return pids;
74
+ } catch {
75
+ // lsof 没找到任何占用,正常情况
76
+ return [];
77
+ }
78
+ }
79
+
40
80
  const managed = [];
41
81
 
42
82
  function startProcess({ name, command, args, logFileName }) {
@@ -69,6 +109,10 @@ function startProcess({ name, command, args, logFileName }) {
69
109
  return child;
70
110
  }
71
111
 
112
+ // 先清掉可能残留的孤儿进程,再启动新子进程
113
+ killOrphansByPort(CLIENT_DEV_PORT);
114
+ killOrphansByPort(HEALTH_PORT);
115
+
72
116
  startProcess({
73
117
  name: 'client',
74
118
  command: 'npx',
@@ -87,6 +131,8 @@ let stopping = false;
87
131
  function cleanup(signal) {
88
132
  if (stopping) return;
89
133
  stopping = true;
134
+ log(`cleanup triggered by ${signal}`);
135
+
90
136
  for (const { child } of managed) {
91
137
  if (!child.pid) continue;
92
138
  try { process.kill(-child.pid, signal || 'SIGTERM'); } catch {}
@@ -96,12 +142,19 @@ function cleanup(signal) {
96
142
  if (!child.pid) continue;
97
143
  try { process.kill(-child.pid, 'SIGKILL'); } catch {}
98
144
  }
145
+ // 兜底再扫一次端口,确保孤儿被清理
146
+ killOrphansByPort(CLIENT_DEV_PORT);
147
+ killOrphansByPort(HEALTH_PORT);
99
148
  process.exit(0);
100
149
  }, 2000);
101
150
  }
102
151
 
103
152
  process.on('SIGINT', () => cleanup('SIGTERM'));
104
153
  process.on('SIGTERM', () => cleanup('SIGTERM'));
154
+ // pkill -f "npm run dev" 把 npm 杀掉后,dev.cjs 会收到 SIGHUP(controlling
155
+ // tty 关闭),Node 默认行为是直接退出不跑 handler。注册 SIGHUP handler 触发
156
+ // cleanup,让子进程组跟着一起死,避免变孤儿
157
+ process.on('SIGHUP', () => cleanup('SIGTERM'));
105
158
 
106
159
  // 任意子进程退出就触发整体 cleanup,避免半残留
107
160
  Promise.race(