cofluxd 0.5.0 → 0.6.0
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/README.md +2 -1
- package/cofluxd.mjs +46 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,8 @@ cofluxd up # 幂等:零参数即可装/起;已装则按当前
|
|
|
16
16
|
cofluxd status # 服务器/登记(含"等待授权")/服务/连接状态
|
|
17
17
|
cofluxd doctor # 中心网络 + gateway/grant/loopback + daemon 状态分层自检
|
|
18
18
|
cofluxd logs -f # 看 daemon 日志
|
|
19
|
-
cofluxd update #
|
|
19
|
+
cofluxd update # 下载新二进制(不重启;supervisor 有变化时提示用 restart 应用)
|
|
20
|
+
cofluxd restart # 重启 daemon 应用新 supervisor(⚠ 结束本机所有活会话)
|
|
20
21
|
cofluxd down # 停止
|
|
21
22
|
cofluxd uninstall [--purge] # 卸载(--purge 连二进制/配置/凭证一并删)
|
|
22
23
|
```
|
package/cofluxd.mjs
CHANGED
|
@@ -115,6 +115,22 @@ function fdaLabel(status) {
|
|
|
115
115
|
|
|
116
116
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
117
117
|
|
|
118
|
+
function fileSha256(path) {
|
|
119
|
+
try { return crypto.createHash("sha256").update(fs.readFileSync(path)).digest("hex"); } catch { return null; }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// macOS:新落盘的二进制带 com.apple.provenance,launchd 顶层 spawn 会被 AMFI 以
|
|
123
|
+
// OS_REASON_CODESIGNING 静默杀死——即使产物是 Developer ID 签名 + 已公证(2026-07-25
|
|
124
|
+
// v0.13.0 实测仍被连杀)。本地 ad-hoc 重签使其成为"本机产物"绕开该检查;签名威胁模型
|
|
125
|
+
// 不受影响(防的是中心被攻破推恶意产物,靠下载后的 sha256+ed25519 验签,与此无关)。
|
|
126
|
+
function resignMacBinaries(paths) {
|
|
127
|
+
if (!IS_MAC) return;
|
|
128
|
+
for (const p of paths) {
|
|
129
|
+
const r = run("codesign", ["--force", "-s", "-", p]);
|
|
130
|
+
if (r.status !== 0) console.warn(`⚠ 本地重签失败: ${p}(daemon 若被系统杀,手动 codesign --force -s - 该文件后 cofluxd restart)`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
118
134
|
async function download(url, dest) {
|
|
119
135
|
const res = await fetch(url, { redirect: "follow" });
|
|
120
136
|
if (!res.ok) die(`下载失败 HTTP ${res.status}: ${url}\n(该版本/平台的 release 资产是否已发布?)`);
|
|
@@ -145,6 +161,7 @@ async function ensureBinaries({ version, binDir, skipIfPresent }) {
|
|
|
145
161
|
fs.copyFileSync(src, join(BIN_DIR, b));
|
|
146
162
|
fs.chmodSync(join(BIN_DIR, b), 0o755);
|
|
147
163
|
}
|
|
164
|
+
resignMacBinaries([SUP_BIN, WRK_BIN]);
|
|
148
165
|
console.log(`✓ 用本地二进制(${binDir})`);
|
|
149
166
|
return;
|
|
150
167
|
}
|
|
@@ -166,6 +183,7 @@ async function ensureBinaries({ version, binDir, skipIfPresent }) {
|
|
|
166
183
|
await download(`${base}/${b}-${t}`, join(BIN_DIR, b));
|
|
167
184
|
console.log("✓");
|
|
168
185
|
}
|
|
186
|
+
resignMacBinaries([SUP_BIN, WRK_BIN]);
|
|
169
187
|
}
|
|
170
188
|
|
|
171
189
|
// 写 settings.json(daemon 直接读)。
|
|
@@ -298,20 +316,41 @@ function cmdDown() { stopService(); console.log("✓ 已停止"); }
|
|
|
298
316
|
// 只有 supervisor 真正靠这条命令更新——它不自动升级(持 PTY,重启会杀会话,见 plan 017)。
|
|
299
317
|
// worker 运行中会被 server 自动热升级到最新 stable(无需停服);这里顺带刷新的是 worker 的
|
|
300
318
|
// "内置兜底二进制"(supervisor 冷启动/热升级缓存皆无时的 fallback),日常可不管。
|
|
319
|
+
//
|
|
320
|
+
// update 与 restart 拆开(2026-07-25 用户拍板):update 只落盘二进制、绝不重启——替换磁盘
|
|
321
|
+
// 文件对运行中的 supervisor/PTY 零影响;supervisor 内容没变就明说不用重启(大多数发版
|
|
322
|
+
// 都不动 supervisor,旧行为等于白丢一次全部会话)。真正的中断收敛到显式的 `cofluxd restart`。
|
|
301
323
|
async function cmdUpdate(v) {
|
|
302
324
|
if (!fs.existsSync(SETTINGS)) die("尚未安装,先 cofluxd up");
|
|
303
325
|
const version = v.version || "latest";
|
|
326
|
+
const before = fileSha256(SUP_BIN);
|
|
304
327
|
await ensureBinaries({ version, binDir: v["bin-dir"] });
|
|
328
|
+
if (before === fileSha256(SUP_BIN)) {
|
|
329
|
+
console.log("✓ 已更新:supervisor 无变化——不需要重启,活会话不受影响");
|
|
330
|
+
console.log(" worker 由 server 自动热升级;本次刷新的只是兜底 worker 二进制。");
|
|
331
|
+
} else {
|
|
332
|
+
console.log(`✓ 新 supervisor 已就位(${v["bin-dir"] ? "本地产物" : version}),但尚未生效`);
|
|
333
|
+
console.log(" ⚠ 运行 `cofluxd restart` 应用——会重启 daemon 并结束本机所有活会话(PTY 随 supervisor 退出)。");
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// 唯一会主动中断会话的命令:应用已就位的新 supervisor(或单纯重启 daemon)。
|
|
338
|
+
function cmdRestart() {
|
|
339
|
+
if (!fs.existsSync(SETTINGS)) die("尚未安装,先 cofluxd up");
|
|
340
|
+
console.log("⚠ 正在重启 daemon:本机所有活会话将结束(PTY 随 supervisor 退出)…");
|
|
305
341
|
restartService();
|
|
306
|
-
console.log(
|
|
307
|
-
console.log(" worker 由 server 自动热升级,通常无需手动更新;此命令只更新 supervisor(及其兜底 worker 二进制)。");
|
|
342
|
+
console.log("✓ 已重启(cofluxd status 查看状态)");
|
|
308
343
|
}
|
|
309
344
|
|
|
310
345
|
// launchd(macOS) / systemd --user(Linux) 服务活跃态查询,status 与 doctor 共用。
|
|
346
|
+
// macOS 必须以 launchctl list 输出里的 PID 为准:label 登记 ≠ 进程存活(supervisor 被
|
|
347
|
+
// OS_REASON_CODESIGNING 杀掉时 label 仍在,旧实现会报假"运行中",2026-07-25 实测踩过)。
|
|
311
348
|
function serviceRunningInfo() {
|
|
312
349
|
if (IS_MAC) {
|
|
313
|
-
const
|
|
314
|
-
|
|
350
|
+
const out = run("launchctl", ["list", "com.coflux.daemon"]);
|
|
351
|
+
const registered = out.status === 0;
|
|
352
|
+
const running = registered && /"PID"\s*=\s*\d+/.test(out.stdout || "");
|
|
353
|
+
return { running, active: running ? "运行中" : registered ? "已登记但进程不在(看 cofluxd logs;常见于系统拒签杀进程)" : "未运行" };
|
|
315
354
|
}
|
|
316
355
|
if (IS_LINUX) {
|
|
317
356
|
const active = (run("systemctl", ["--user", "is-active", "coflux-daemon.service"]).stdout || "").trim() || "未运行";
|
|
@@ -631,7 +670,8 @@ const HELP = `cofluxd —— coflux daemon 管理
|
|
|
631
670
|
cofluxd up [flags] 幂等:首次装+起,已装则按当前 settings.json 重装服务并重启
|
|
632
671
|
cofluxd status 服务器/登记(含"等待授权")/服务/连接状态
|
|
633
672
|
cofluxd doctor 中心网络 + gateway bind/grant/loopback + daemon 状态分层自检
|
|
634
|
-
cofluxd update
|
|
673
|
+
cofluxd update 下载新二进制(不重启;supervisor 有变化时提示用 restart 应用)
|
|
674
|
+
cofluxd restart 重启 daemon 应用新 supervisor(⚠ 结束本机所有活会话)
|
|
635
675
|
cofluxd fda [仅 macOS] 引导授予完全磁盘访问权限(避免 PTY 因 TCC 弹窗卡住)
|
|
636
676
|
cofluxd logs [-f] 看 daemon 日志
|
|
637
677
|
cofluxd down 停止
|
|
@@ -667,7 +707,7 @@ let cmd = positionals[0];
|
|
|
667
707
|
if (values.help || cmd === "help") { console.log(HELP); process.exit(0); }
|
|
668
708
|
if (!cmd) cmd = fs.existsSync(SETTINGS) ? "status" : "up"; // 首次裸跑 → 引导
|
|
669
709
|
|
|
670
|
-
const handlers = { up: cmdUp, update: cmdUpdate, down: cmdDown, status: cmdStatus, doctor: cmdDoctor, fda: cmdFda, logs: cmdLogs, uninstall: cmdUninstall };
|
|
710
|
+
const handlers = { up: cmdUp, update: cmdUpdate, restart: cmdRestart, down: cmdDown, status: cmdStatus, doctor: cmdDoctor, fda: cmdFda, logs: cmdLogs, uninstall: cmdUninstall };
|
|
671
711
|
const h = handlers[cmd];
|
|
672
712
|
if (!h) die(`未知命令: ${cmd}${MIGRATED[cmd] ? `\n${MIGRATED[cmd]}` : ""}\n\n${HELP}`);
|
|
673
713
|
await h(values);
|