@wu529778790/open-im 1.5.5-beta.3 → 1.5.5-beta.4

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/dist/cli.js CHANGED
@@ -2,8 +2,9 @@
2
2
  import { main, needsSetup, runInteractiveSetup } from "./index.js";
3
3
  import { loadConfig } from "./config.js";
4
4
  import { checkAndUpdate } from "./check-update.js";
5
- import { getWebConfigUrl, runWebConfigFlow } from "./config-web.js";
6
- import { getServiceStatus, removePid, startBackgroundService, stopBackgroundService } from "./service-control.js";
5
+ import { getWebConfigUrl, openWebConfigUrl, runWebConfigFlow } from "./config-web.js";
6
+ import { getManagerStatus, startManagerProcess, stopManagerProcess } from "./manager-control.js";
7
+ import { stopBackgroundService } from "./service-control.js";
7
8
  async function ensureConfigured(mode) {
8
9
  const forceWeb = process.env.OPEN_IM_FORCE_WEB === "1";
9
10
  if (mode !== "init" && !needsSetup()) {
@@ -30,80 +31,83 @@ async function ensureConfigured(mode) {
30
31
  return false;
31
32
  }
32
33
  }
33
- // ============================================================================
34
- // 命令处理
35
- // ============================================================================
36
34
  async function cmdStart() {
37
- const status = getServiceStatus();
35
+ const status = getManagerStatus();
38
36
  if (status.running && status.pid) {
39
- console.log("\n🟢 open-im 已在后台运行");
40
- console.log(` pid: ${status.pid}`);
41
- console.log(` 配置页: ${getWebConfigUrl()}`);
37
+ console.log("\nopen-im is already running in the background.");
38
+ console.log(` pid: ${status.pid}`);
39
+ console.log(` config page: ${getWebConfigUrl()}`);
42
40
  return;
43
41
  }
44
- removePid();
45
42
  if (!(await ensureConfigured("start"))) {
46
43
  process.exit(1);
47
44
  }
48
- // 检查并自动更新到最新版本
49
45
  const { updated } = await checkAndUpdate();
50
46
  if (updated) {
51
47
  process.exit(0);
52
48
  }
53
49
  process.env.OPEN_IM_AUTO_OPEN_CONFIG_ONCE = "1";
54
- const child = startBackgroundService(process.cwd());
55
- delete process.env.OPEN_IM_AUTO_OPEN_CONFIG_ONCE;
56
- console.log("\n🟢 open-im 已在后台启动");
57
- console.log(` pid: ${child.pid}`);
58
- console.log(` 配置页: ${getWebConfigUrl()}`);
50
+ try {
51
+ const child = await startManagerProcess(process.cwd());
52
+ console.log("\nopen-im started in the background.");
53
+ console.log(` pid: ${child.pid}`);
54
+ console.log(` config page: ${getWebConfigUrl()}`);
55
+ }
56
+ finally {
57
+ delete process.env.OPEN_IM_AUTO_OPEN_CONFIG_ONCE;
58
+ }
59
59
  }
60
60
  async function cmdStop() {
61
- const status = getServiceStatus();
61
+ const status = getManagerStatus();
62
62
  if (!status.pid) {
63
- console.log("open-im 未在后台运行");
63
+ console.log("open-im is not running in the background.");
64
64
  return;
65
65
  }
66
- const result = await stopBackgroundService();
67
- console.log("\n🔴 open-im 已停止");
68
- console.log(` pid: ${result.pid}`);
66
+ await stopBackgroundService();
67
+ const result = await stopManagerProcess();
68
+ console.log("\nopen-im stopped.");
69
+ console.log(` pid: ${result.pid}`);
69
70
  }
70
71
  async function cmdInit() {
71
- console.log("\n━━━ open-im 本地控制台 ━━━\n");
72
+ console.log("\nopen-im local control\n");
73
+ const status = getManagerStatus();
74
+ if (status.running && status.pid) {
75
+ openWebConfigUrl();
76
+ console.log(`Config page is already running: ${getWebConfigUrl()}`);
77
+ return;
78
+ }
72
79
  const saved = await ensureConfigured("init");
73
80
  if (!saved) {
74
- console.log("\n❌ 配置未完成,已取消。");
81
+ console.log("\nConfiguration was not completed.");
75
82
  process.exit(1);
76
83
  }
77
- console.log("\n✅ 配置完成!");
78
- console.log("\n现在可以运行以下命令启动服务:");
84
+ console.log("\nConfiguration saved.");
85
+ console.log("\nYou can start the app with:");
79
86
  console.log(" open-im start");
80
87
  console.log(" open-im dev");
81
88
  }
82
89
  async function cmdDev() {
83
90
  if (!(await ensureConfigured("dev"))) {
84
- console.log("配置未完成,已取消启动。");
91
+ console.log("Configuration was not completed.");
85
92
  process.exit(1);
86
93
  }
87
94
  await main();
88
95
  }
89
96
  function showHelp(exitCode = 0) {
90
97
  console.log(`
91
- 用法: open-im <command>
98
+ Usage: open-im <command>
92
99
 
93
- 命令:
94
- start 后台运行服务
95
- stop 停止后台服务
96
- init 打开本地 Web 配置页
97
- dev 前台运行(调试模式),Ctrl+C 停止
100
+ Commands:
101
+ start Run the full app in the background
102
+ stop Stop the full app
103
+ init Open the local web configuration page
104
+ dev Run in the foreground for debugging
98
105
 
99
- 选项:
100
- -h, --help 显示此帮助信息
106
+ Options:
107
+ -h, --help Show this help message
101
108
  `);
102
109
  process.exit(exitCode);
103
110
  }
104
- // ============================================================================
105
- // 命令路由
106
- // ============================================================================
107
111
  const cmd = process.argv[2];
108
112
  const commands = {
109
113
  start: cmdStart,
@@ -127,6 +131,6 @@ else if (commands[cmd]) {
127
131
  });
128
132
  }
129
133
  else {
130
- console.error(`未知命令: ${cmd}`);
134
+ console.error(`Unknown command: ${cmd}`);
131
135
  showHelp(1);
132
136
  }
@@ -288,8 +288,8 @@ const PAGE_HTML = String.raw `<!doctype html>
288
288
  <div class="actions">
289
289
  <button id="validateButton" class="warning">Validate</button>
290
290
  <button id="saveButton" class="secondary">Save config</button>
291
- <button id="startButton">Start service</button>
292
- <button id="stopButton" class="danger">Stop service</button>
291
+ <button id="startButton">Start bridge</button>
292
+ <button id="stopButton" class="danger">Stop bridge</button>
293
293
  </div>
294
294
  <div class="message" id="message"></div>
295
295
  </section>
@@ -315,7 +315,7 @@ const PAGE_HTML = String.raw `<!doctype html>
315
315
  const payload = () => ({ platforms: { telegram: { enabled: el("telegram-enabled").checked, botToken: el("telegram-botToken").value, proxy: el("telegram-proxy").value, allowedUserIds: el("telegram-allowedUserIds").value }, feishu: { enabled: el("feishu-enabled").checked, appId: el("feishu-appId").value, appSecret: el("feishu-appSecret").value, allowedUserIds: el("feishu-allowedUserIds").value }, wework: { enabled: el("wework-enabled").checked, corpId: el("wework-corpId").value, secret: el("wework-secret").value, allowedUserIds: el("wework-allowedUserIds").value }, dingtalk: { enabled: el("dingtalk-enabled").checked, clientId: el("dingtalk-clientId").value, clientSecret: el("dingtalk-clientSecret").value, cardTemplateId: el("dingtalk-cardTemplateId").value, allowedUserIds: el("dingtalk-allowedUserIds").value } }, ai: { aiCommand: el("ai-aiCommand").value, claudeCliPath: el("ai-claudeCliPath").value, claudeWorkDir: el("ai-claudeWorkDir").value, claudeSkipPermissions: el("ai-claudeSkipPermissions").checked, claudeTimeoutMs: Number(el("ai-claudeTimeoutMs").value || "0"), claudeModel: el("ai-claudeModel").value, cursorCliPath: el("ai-cursorCliPath").value, codexCliPath: el("ai-codexCliPath").value, codexProxy: el("ai-codexProxy").value, hookPort: Number(el("ai-hookPort").value || "0"), logLevel: el("ai-logLevel").value, useSdkMode: el("ai-useSdkMode").checked } });
316
316
  async function request(path, options={}) { const response = await fetch(path, { headers: { "content-type": "application/json" }, ...options }); const body = await response.json(); if (!response.ok) throw new Error(body.error || "Request failed"); return body; }
317
317
  function fill(data, meta) { el("configPath").textContent = meta.configPath; el("modeBadge").textContent = "Flow: " + meta.mode; el("telegram-enabled").checked = data.platforms.telegram.enabled; el("telegram-botToken").value = data.platforms.telegram.botToken; el("telegram-proxy").value = data.platforms.telegram.proxy; el("telegram-allowedUserIds").value = data.platforms.telegram.allowedUserIds; el("feishu-enabled").checked = data.platforms.feishu.enabled; el("feishu-appId").value = data.platforms.feishu.appId; el("feishu-appSecret").value = data.platforms.feishu.appSecret; el("feishu-allowedUserIds").value = data.platforms.feishu.allowedUserIds; el("wework-enabled").checked = data.platforms.wework.enabled; el("wework-corpId").value = data.platforms.wework.corpId; el("wework-secret").value = data.platforms.wework.secret; el("wework-allowedUserIds").value = data.platforms.wework.allowedUserIds; el("dingtalk-enabled").checked = data.platforms.dingtalk.enabled; el("dingtalk-clientId").value = data.platforms.dingtalk.clientId; el("dingtalk-clientSecret").value = data.platforms.dingtalk.clientSecret; el("dingtalk-cardTemplateId").value = data.platforms.dingtalk.cardTemplateId; el("dingtalk-allowedUserIds").value = data.platforms.dingtalk.allowedUserIds; el("ai-aiCommand").value = data.ai.aiCommand; el("ai-claudeCliPath").value = data.ai.claudeCliPath; el("ai-claudeWorkDir").value = data.ai.claudeWorkDir; el("ai-claudeSkipPermissions").checked = data.ai.claudeSkipPermissions; el("ai-claudeTimeoutMs").value = String(data.ai.claudeTimeoutMs); el("ai-claudeModel").value = data.ai.claudeModel; el("ai-cursorCliPath").value = data.ai.cursorCliPath; el("ai-codexCliPath").value = data.ai.codexCliPath; el("ai-codexProxy").value = data.ai.codexProxy; el("ai-hookPort").value = String(data.ai.hookPort); el("ai-logLevel").value = data.ai.logLevel; el("ai-useSdkMode").checked = data.ai.useSdkMode; updateVisualState(); }
318
- async function refreshStatus() { const data = await request("/api/service/status"); el("serviceState").textContent = data.running ? ("Service running (pid " + data.pid + ")") : "Service stopped"; el("statusMeta").textContent = data.running ? "Background bridge process is active." : "No background bridge process is active."; }
318
+ async function refreshStatus() { const data = await request("/api/service/status"); el("serviceState").textContent = data.running ? ("Bridge running (pid " + data.pid + ")") : "Bridge stopped"; el("statusMeta").textContent = data.running ? "Bridge worker is active." : "Bridge worker is currently stopped."; }
319
319
  async function boot() { setBusy(true); try { const data = await request("/api/config"); fill(data.payload, data.meta); await refreshStatus(); setMessage("Control surface ready.", "success"); } catch (error) { setMessage(error.message || String(error), "error"); } finally { setBusy(false); } setInterval(() => { refreshStatus().catch(() => {}); }, 5000); ids.forEach((id) => { const node = el(id); if (node) node.addEventListener("input", updateVisualState); if (node) node.addEventListener("change", updateVisualState); }); }
320
320
  async function validate() { setBusy(true); try { const data = await request("/api/config/validate", { method: "POST", body: JSON.stringify(payload()) }); setMessage(data.message, "success"); } catch (error) { setMessage(error.message || String(error), "error"); } finally { setBusy(false); } }
321
321
  async function save() { setBusy(true); try { const data = await request("/api/config/save?final=1", { method: "POST", body: JSON.stringify(payload()) }); setMessage(data.message, "success"); } catch (error) { setMessage(error.message || String(error), "error"); } finally { setBusy(false); } }
@@ -400,7 +400,7 @@ export async function startWebConfigServer(options) {
400
400
  try {
401
401
  loadConfig();
402
402
  const started = startBackgroundService(options.cwd);
403
- json(response, 200, { message: `Background service started with pid ${started.pid}.`, pid: started.pid });
403
+ json(response, 200, { message: `Bridge started with pid ${started.pid}.`, pid: started.pid });
404
404
  if (!options.persistent) {
405
405
  setTimeout(() => finishFlow("saved"), 120);
406
406
  }
@@ -413,7 +413,7 @@ export async function startWebConfigServer(options) {
413
413
  if (request.method === "POST" && requestUrl.pathname === "/api/service/stop") {
414
414
  try {
415
415
  const result = await stopBackgroundService();
416
- json(response, 200, { message: result.pid ? `Background service stopped (pid ${result.pid}).` : "No background service was running." });
416
+ json(response, 200, { message: result.pid ? `Bridge stopped (pid ${result.pid}).` : "Bridge was already stopped." });
417
417
  }
418
418
  catch (error) {
419
419
  json(response, 400, { error: error instanceof Error ? error.message : String(error) });
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { writeFileSync, existsSync, mkdirSync, unlinkSync } from "node:fs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { loadConfig, needsSetup } from "./config.js";
5
5
  import { runInteractiveSetup, runClaudeApiSetup } from "./setup.js";
6
- import { openWebConfigUrl, runWebConfigFlow, startWebConfigServer } from "./config-web.js";
6
+ import { runWebConfigFlow } from "./config-web.js";
7
7
  // 导出供 cli.ts 使用
8
8
  export { needsSetup, runInteractiveSetup };
9
9
  import { initTelegram, stopTelegram } from "./telegram/client.js";
@@ -30,7 +30,6 @@ import { initPermissionModes } from "./permission-mode/session-mode.js";
30
30
  import { createRequire } from "node:module";
31
31
  const require = createRequire(import.meta.url);
32
32
  const { version: APP_VERSION } = require("../package.json");
33
- const CONFIG_UI_ONCE_FILE = join(APP_HOME, ".config-ui-once");
34
33
  const log = createLogger("Main");
35
34
  async function sendLifecycleNotification(platform, message) {
36
35
  const telegramChatId = getActiveChatId("telegram");
@@ -121,20 +120,6 @@ export async function main() {
121
120
  initLogger(config.logDir, config.logLevel);
122
121
  loadActiveChats();
123
122
  initPermissionModes();
124
- let configWebServer = null;
125
- try {
126
- configWebServer = await startWebConfigServer({ mode: "start", cwd: process.cwd(), persistent: true });
127
- log.info(`Web config page available at ${configWebServer.url}`);
128
- if (process.env.OPEN_IM_AUTO_OPEN_CONFIG_ONCE === "1" && !existsSync(CONFIG_UI_ONCE_FILE)) {
129
- if (!existsSync(APP_HOME))
130
- mkdirSync(APP_HOME, { recursive: true });
131
- writeFileSync(CONFIG_UI_ONCE_FILE, "1", "utf-8");
132
- openWebConfigUrl();
133
- }
134
- }
135
- catch (error) {
136
- log.warn("Failed to start web config page:", error);
137
- }
138
123
  // 当配置为跳过权限时,设置 CC_SKIP_PERMISSIONS 让权限服务器自动放行
139
124
  // 否则 Cursor/Claude 请求工具权限时会卡住等待用户 /allow
140
125
  if (config.claudeSkipPermissions) {
@@ -256,7 +241,6 @@ export async function main() {
256
241
  dingtalkHandle?.stop();
257
242
  stopDingTalk();
258
243
  stopPermissionServer();
259
- await configWebServer?.close().catch(() => { });
260
244
  sessionManager.destroy();
261
245
  cleanupAdapters();
262
246
  flushActiveChats();
@@ -0,0 +1,17 @@
1
+ export declare function getManagerPid(): number | null;
2
+ export declare function removeManagerPid(): void;
3
+ export declare function removeManagerReady(): void;
4
+ export declare function writeManagerReady(): void;
5
+ export declare function isManagerReady(): boolean;
6
+ export declare function writeManagerPid(pid: number): void;
7
+ export declare function getManagerStatus(): {
8
+ running: boolean;
9
+ pid: number | null;
10
+ };
11
+ export declare function startManagerProcess(cwd: string): Promise<{
12
+ pid: number;
13
+ }>;
14
+ export declare function stopManagerProcess(): Promise<{
15
+ pid: number | null;
16
+ stopped: boolean;
17
+ }>;
@@ -0,0 +1,160 @@
1
+ import { execFileSync, spawn } from "node:child_process";
2
+ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import { dirname, extname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { APP_HOME } from "./constants.js";
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const PID_FILE = join(APP_HOME, "open-im.pid");
8
+ const READY_FILE = join(APP_HOME, "open-im.ready");
9
+ function getManagerEntry() {
10
+ const extension = extname(fileURLToPath(import.meta.url));
11
+ if (extension === ".ts") {
12
+ return {
13
+ command: process.execPath,
14
+ args: ["--import", "tsx", join(__dirname, "manager.ts")],
15
+ };
16
+ }
17
+ return {
18
+ command: process.execPath,
19
+ args: [join(__dirname, "manager.js")],
20
+ };
21
+ }
22
+ function isRunning(pid) {
23
+ try {
24
+ if (process.platform === "win32") {
25
+ const result = execFileSync("tasklist", ["/FI", `PID eq ${pid}`, "/NH"], {
26
+ stdio: "pipe",
27
+ windowsHide: true,
28
+ }).toString();
29
+ return result.includes(String(pid));
30
+ }
31
+ process.kill(pid, 0);
32
+ return true;
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ }
38
+ export function getManagerPid() {
39
+ if (!existsSync(PID_FILE))
40
+ return null;
41
+ try {
42
+ const pid = parseInt(readFileSync(PID_FILE, "utf-8").trim(), 10);
43
+ return Number.isNaN(pid) ? null : pid;
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ }
49
+ export function removeManagerPid() {
50
+ try {
51
+ if (existsSync(PID_FILE))
52
+ unlinkSync(PID_FILE);
53
+ }
54
+ catch {
55
+ /* ignore */
56
+ }
57
+ }
58
+ export function removeManagerReady() {
59
+ try {
60
+ if (existsSync(READY_FILE))
61
+ unlinkSync(READY_FILE);
62
+ }
63
+ catch {
64
+ /* ignore */
65
+ }
66
+ }
67
+ export function writeManagerReady() {
68
+ if (!existsSync(APP_HOME))
69
+ mkdirSync(APP_HOME, { recursive: true });
70
+ writeFileSync(READY_FILE, "1", "utf-8");
71
+ }
72
+ export function isManagerReady() {
73
+ return existsSync(READY_FILE);
74
+ }
75
+ export function writeManagerPid(pid) {
76
+ if (!existsSync(APP_HOME))
77
+ mkdirSync(APP_HOME, { recursive: true });
78
+ writeFileSync(PID_FILE, String(pid), "utf-8");
79
+ }
80
+ export function getManagerStatus() {
81
+ const pid = getManagerPid();
82
+ if (!pid)
83
+ return { running: false, pid: null };
84
+ if (!isRunning(pid)) {
85
+ removeManagerReady();
86
+ removeManagerPid();
87
+ return { running: false, pid: null };
88
+ }
89
+ return { running: true, pid };
90
+ }
91
+ export async function startManagerProcess(cwd) {
92
+ const current = getManagerStatus();
93
+ if (current.running && current.pid) {
94
+ if (isManagerReady()) {
95
+ return { pid: current.pid };
96
+ }
97
+ throw new Error("Manager process exists but is not ready yet.");
98
+ }
99
+ removeManagerReady();
100
+ removeManagerPid();
101
+ const entry = getManagerEntry();
102
+ const child = spawn(entry.command, entry.args, {
103
+ detached: true,
104
+ stdio: "ignore",
105
+ cwd,
106
+ env: process.env,
107
+ windowsHide: process.platform === "win32",
108
+ });
109
+ child.unref();
110
+ if (!child.pid) {
111
+ throw new Error("Failed to start manager process.");
112
+ }
113
+ writeManagerPid(child.pid);
114
+ const deadline = Date.now() + 8000;
115
+ while (Date.now() < deadline) {
116
+ await new Promise((resolve) => setTimeout(resolve, 100));
117
+ if (!isRunning(child.pid)) {
118
+ removeManagerReady();
119
+ removeManagerPid();
120
+ throw new Error("Manager process exited before becoming ready.");
121
+ }
122
+ if (isManagerReady()) {
123
+ return { pid: child.pid };
124
+ }
125
+ }
126
+ removeManagerReady();
127
+ removeManagerPid();
128
+ try {
129
+ process.kill(child.pid, "SIGTERM");
130
+ }
131
+ catch {
132
+ /* ignore */
133
+ }
134
+ throw new Error("Manager process did not become ready in time.");
135
+ }
136
+ export async function stopManagerProcess() {
137
+ const pid = getManagerPid();
138
+ if (!pid) {
139
+ removeManagerReady();
140
+ return { pid: null, stopped: false };
141
+ }
142
+ if (!isRunning(pid)) {
143
+ removeManagerReady();
144
+ removeManagerPid();
145
+ return { pid, stopped: true };
146
+ }
147
+ try {
148
+ process.kill(pid, "SIGTERM");
149
+ await new Promise((resolve) => setTimeout(resolve, 500));
150
+ }
151
+ catch {
152
+ /* ignore */
153
+ }
154
+ if (isRunning(pid)) {
155
+ process.kill(pid, "SIGKILL");
156
+ }
157
+ removeManagerReady();
158
+ removeManagerPid();
159
+ return { pid, stopped: true };
160
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { APP_HOME } from "./constants.js";
4
+ import { openWebConfigUrl, startWebConfigServer } from "./config-web.js";
5
+ import { removeManagerPid, removeManagerReady, writeManagerReady } from "./manager-control.js";
6
+ import { startBackgroundService, stopBackgroundService } from "./service-control.js";
7
+ const CONFIG_UI_ONCE_FILE = join(APP_HOME, ".config-ui-once");
8
+ async function main() {
9
+ const web = await startWebConfigServer({ mode: "start", cwd: process.cwd(), persistent: true });
10
+ startBackgroundService(process.cwd());
11
+ writeManagerReady();
12
+ if (process.env.OPEN_IM_AUTO_OPEN_CONFIG_ONCE === "1" && !existsSync(CONFIG_UI_ONCE_FILE)) {
13
+ if (!existsSync(APP_HOME))
14
+ mkdirSync(APP_HOME, { recursive: true });
15
+ writeFileSync(CONFIG_UI_ONCE_FILE, "1", "utf-8");
16
+ openWebConfigUrl();
17
+ }
18
+ const shutdown = async () => {
19
+ await web.close().catch(() => { });
20
+ await stopBackgroundService().catch(() => { });
21
+ removeManagerReady();
22
+ removeManagerPid();
23
+ process.exit(0);
24
+ };
25
+ process.on("SIGINT", () => shutdown().catch(() => process.exit(1)));
26
+ process.on("SIGTERM", () => shutdown().catch(() => process.exit(1)));
27
+ }
28
+ const isEntry = process.argv[1]?.replace(/\\/g, "/").endsWith("/manager.js") ||
29
+ process.argv[1]?.replace(/\\/g, "/").endsWith("/manager.ts");
30
+ if (isEntry) {
31
+ main().catch((error) => {
32
+ console.error("Manager fatal error:", error);
33
+ removeManagerReady();
34
+ removeManagerPid();
35
+ process.exit(1);
36
+ });
37
+ }
@@ -4,7 +4,7 @@ import { dirname, extname, join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { APP_HOME, SHUTDOWN_PORT } from "./constants.js";
6
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
7
- const PID_FILE = join(APP_HOME, "open-im.pid");
7
+ const PID_FILE = join(APP_HOME, "open-im-worker.pid");
8
8
  const PORT_FILE = join(APP_HOME, "open-im.port");
9
9
  function getServiceEntry() {
10
10
  const extension = extname(fileURLToPath(import.meta.url));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wu529778790/open-im",
3
- "version": "1.5.5-beta.3",
3
+ "version": "1.5.5-beta.4",
4
4
  "description": "Multi-platform IM bridge for AI CLI tools (Claude, Codex, Cursor)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",