oh-my-im 0.1.8 → 0.1.9

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.
Files changed (2) hide show
  1. package/dist/omi.js +67 -9
  2. package/package.json +1 -1
package/dist/omi.js CHANGED
@@ -98,6 +98,44 @@ function isRunning(pid) {
98
98
  return false;
99
99
  }
100
100
  }
101
+ function omiProcesses() {
102
+ try {
103
+ const result = spawnSync("ps", ["-eo", "pid=,ppid=,args="], { encoding: "utf8" });
104
+ if (result.status !== 0 || typeof result.stdout !== "string")
105
+ return [];
106
+ return result.stdout.split("\\n").flatMap((line) => {
107
+ const match = line.trim().match(/^(\\d+)\\s+(\\d+)\\s+(.+)$/);
108
+ if (!match)
109
+ return [];
110
+ return [{ pid: Number(match[1]), ppid: Number(match[2]), command: match[3] }];
111
+ });
112
+ }
113
+ catch {
114
+ return [];
115
+ }
116
+ }
117
+ function allOmiProcessIds() {
118
+ const processes = omiProcesses();
119
+ const ids = new Set();
120
+ // Match only this application's built workers. Do not use a broad
121
+ // "oh-my-im" substring that could terminate an unrelated shell/editor.
122
+ processes.filter((item) => item.command.includes("/dist/omi.js") || item.command.includes("/dist/dashboard-worker.js") || item.command.includes("/dist/dws-listener.js") || item.command.includes("/dist/bot-worker.js"))
123
+ .forEach((item) => ids.add(item.pid));
124
+ // Include Agent/DWS descendants spawned by our workers, such as codex/pi and
125
+ // dws child processes, so stop really leaves no worker behind.
126
+ let changed = true;
127
+ while (changed) {
128
+ changed = false;
129
+ processes.forEach((item) => {
130
+ if (ids.has(item.ppid) && !ids.has(item.pid)) {
131
+ ids.add(item.pid);
132
+ changed = true;
133
+ }
134
+ });
135
+ }
136
+ ids.delete(process.pid);
137
+ return [...ids];
138
+ }
101
139
  function pidFromFile(path) {
102
140
  try {
103
141
  const pid = Number.parseInt(readFileSync(path, "utf8").trim(), 10);
@@ -182,21 +220,41 @@ function start(mode, workspace = launchWorkspace) {
182
220
  }
183
221
  async function stop() {
184
222
  const current = readState();
185
- if (!current) {
223
+ const statePids = current?.processes.map((managed) => managed.pid) ?? [];
224
+ const pids = [...new Set([...statePids, ...allOmiProcessIds()])].filter((pid) => pid !== process.pid && isRunning(pid));
225
+ if (pids.length === 0) {
226
+ if (existsSync(stateFile))
227
+ unlinkSync(stateFile);
186
228
  console.log("omi is not running");
187
229
  return false;
188
230
  }
189
- for (const managed of current.processes)
190
- process.kill(managed.pid, "SIGTERM");
231
+ // Stop every omi worker and its descendants, including stale workers left by
232
+ // an older state file. Escalate after five seconds so restart cannot overlap
233
+ // with the previous listener/bot instance.
234
+ for (const pid of pids) {
235
+ try {
236
+ process.kill(pid, "SIGTERM");
237
+ }
238
+ catch { /* already exited */ }
239
+ }
191
240
  const deadline = Date.now() + 5_000;
192
- while (current.processes.some((process) => isRunning(process.pid)) && Date.now() < deadline) {
241
+ while (pids.some((pid) => isRunning(pid)) && Date.now() < deadline) {
193
242
  await new Promise((resolve) => setTimeout(resolve, 100));
194
243
  }
195
- const active = current.processes.filter((process) => isRunning(process.pid));
196
- if (active.length > 0)
197
- throw new Error(`omi did not stop within 5 seconds (pid ${active.map((item) => item.pid).join(", ")})`);
198
- unlinkSync(stateFile);
199
- console.log("omi stopped");
244
+ const active = pids.filter((pid) => isRunning(pid));
245
+ for (const pid of active) {
246
+ try {
247
+ process.kill(pid, "SIGKILL");
248
+ }
249
+ catch { /* already exited */ }
250
+ }
251
+ await new Promise((resolve) => setTimeout(resolve, 100));
252
+ const remaining = pids.filter((pid) => isRunning(pid));
253
+ if (remaining.length > 0)
254
+ throw new Error(`omi did not stop (pid ${remaining.join(", ")})`);
255
+ if (existsSync(stateFile))
256
+ unlinkSync(stateFile);
257
+ console.log(`omi stopped (${pids.length} process(es))`);
200
258
  return true;
201
259
  }
202
260
  function status() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-im",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "author": {
5
5
  "name": "杜振训",
6
6
  "email": "duzhenxun@126.com"