morpheus-cli 0.4.2 → 0.4.3
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.
|
@@ -4,7 +4,7 @@ import fs from 'fs-extra';
|
|
|
4
4
|
import { confirm } from '@inquirer/prompts';
|
|
5
5
|
import { scaffold } from '../../runtime/scaffold.js';
|
|
6
6
|
import { DisplayManager } from '../../runtime/display.js';
|
|
7
|
-
import { writePid, readPid, isProcessRunning, clearPid, checkStalePid, killProcess } from '../../runtime/lifecycle.js';
|
|
7
|
+
import { writePid, readPid, isProcessRunning, clearPid, checkStalePid, killProcess, waitForProcessDeath } from '../../runtime/lifecycle.js';
|
|
8
8
|
import { ConfigManager } from '../../config/manager.js';
|
|
9
9
|
import { renderBanner } from '../utils/render.js';
|
|
10
10
|
import { TelegramAdapter } from '../../channels/telegram.js';
|
|
@@ -28,7 +28,8 @@ export const startCommand = new Command('start')
|
|
|
28
28
|
// Cleanup stale PID first
|
|
29
29
|
await checkStalePid();
|
|
30
30
|
const existingPid = await readPid();
|
|
31
|
-
if (
|
|
31
|
+
// Guard: skip if the stored PID is our own (container restart PID reuse scenario)
|
|
32
|
+
if (existingPid !== null && existingPid !== process.pid && isProcessRunning(existingPid)) {
|
|
32
33
|
display.log(chalk.yellow(`Morpheus is already running (PID: ${existingPid})`));
|
|
33
34
|
let shouldKill = options.yes;
|
|
34
35
|
if (!shouldKill) {
|
|
@@ -48,10 +49,13 @@ export const startCommand = new Command('start')
|
|
|
48
49
|
display.log(chalk.cyan(`Stopping existing process (PID: ${existingPid})...`));
|
|
49
50
|
const killed = killProcess(existingPid);
|
|
50
51
|
if (killed) {
|
|
51
|
-
display.log(chalk.green('
|
|
52
|
+
display.log(chalk.green('Terminated'));
|
|
52
53
|
await clearPid();
|
|
53
|
-
//
|
|
54
|
-
|
|
54
|
+
// Wait up to 5 s for the process to actually die before continuing
|
|
55
|
+
const died = await waitForProcessDeath(existingPid, 5000);
|
|
56
|
+
if (!died) {
|
|
57
|
+
display.log(chalk.yellow('Warning: process may still be running. Proceeding anyway.'));
|
|
58
|
+
}
|
|
55
59
|
}
|
|
56
60
|
else {
|
|
57
61
|
display.log(chalk.red('Failed to stop the process'));
|
|
@@ -31,15 +31,37 @@ export function isProcessRunning(pid) {
|
|
|
31
31
|
return e.code === 'EPERM'; // If EPERM, it exists but we lack permission (still running)
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Waits until the given PID is no longer running, or until timeout is reached.
|
|
36
|
+
* Returns true if the process died, false if timeout was reached.
|
|
37
|
+
*/
|
|
38
|
+
export async function waitForProcessDeath(pid, timeoutMs = 5000, intervalMs = 200) {
|
|
39
|
+
const deadline = Date.now() + timeoutMs;
|
|
40
|
+
while (Date.now() < deadline) {
|
|
41
|
+
if (!isProcessRunning(pid))
|
|
42
|
+
return true;
|
|
43
|
+
await new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
44
|
+
}
|
|
45
|
+
return !isProcessRunning(pid);
|
|
46
|
+
}
|
|
34
47
|
export async function checkStalePid() {
|
|
35
48
|
const pid = await readPid();
|
|
36
49
|
if (pid !== null) {
|
|
50
|
+
// Never treat our own PID as stale — this avoids self-kill loops in containers
|
|
51
|
+
// where a restarted process may inherit the same PID that was previously written.
|
|
52
|
+
if (pid === process.pid) {
|
|
53
|
+
await clearPid();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
37
56
|
if (!isProcessRunning(pid)) {
|
|
38
57
|
await clearPid();
|
|
39
58
|
}
|
|
40
59
|
}
|
|
41
60
|
}
|
|
42
61
|
export function killProcess(pid) {
|
|
62
|
+
// Safety guard: never kill ourselves
|
|
63
|
+
if (pid === process.pid)
|
|
64
|
+
return false;
|
|
43
65
|
try {
|
|
44
66
|
process.kill(pid, 'SIGTERM');
|
|
45
67
|
return true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "morpheus-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Morpheus is a local AI agent for developers, running as a CLI daemon that connects to LLMs, local tools, and MCPs, enabling interaction via Terminal, Telegram, and Discord. Inspired by the character Morpheus from *The Matrix*, the project acts as an intelligent orchestrator, bridging the gap between the developer and complex systems.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"morpheus": "./bin/morpheus.js"
|