@tritard/waterbrother 0.16.13 → 0.16.15
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 +1 -1
- package/src/cli.js +105 -7
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -131,6 +131,7 @@ const INTERACTIVE_COMMANDS = [
|
|
|
131
131
|
{ name: "/gateway pairings", description: "List pending Telegram pairing requests" },
|
|
132
132
|
{ name: "/gateway pair <user-id>", description: "Approve a pending Telegram user id" },
|
|
133
133
|
{ name: "/gateway unpair <user-id>", description: "Remove a paired Telegram user id" },
|
|
134
|
+
{ name: "/gateway stop", description: "Stop the tracked Telegram gateway process" },
|
|
134
135
|
{ name: "/channels", description: "Show messaging channel readiness" },
|
|
135
136
|
{ name: "/agent", description: "Show active agent profile" },
|
|
136
137
|
{ name: "/agent <profile>", description: "Switch profile: coder|designer|reviewer|planner" },
|
|
@@ -242,6 +243,7 @@ Usage:
|
|
|
242
243
|
waterbrother channels show <service>
|
|
243
244
|
waterbrother gateway status
|
|
244
245
|
waterbrother gateway run telegram
|
|
246
|
+
waterbrother gateway stop [telegram]
|
|
245
247
|
waterbrother gateway pairings [telegram]
|
|
246
248
|
waterbrother gateway pair [telegram] <user-id>
|
|
247
249
|
waterbrother gateway unpair [telegram] <user-id>
|
|
@@ -2731,22 +2733,21 @@ async function maybeAutostartGateway(runtime, { cwd, io = console } = {}) {
|
|
|
2731
2733
|
: [];
|
|
2732
2734
|
|
|
2733
2735
|
if (!gateway.enabled || !startupChannels.includes("telegram")) {
|
|
2734
|
-
return { attempted: false, started: false, reason: "not-configured" };
|
|
2736
|
+
return { attempted: false, started: false, reason: "not-configured", child: null };
|
|
2735
2737
|
}
|
|
2736
2738
|
|
|
2737
2739
|
const telegram = runtime?.channels?.telegram || {};
|
|
2738
2740
|
if (!telegram.enabled || !String(telegram.botToken || "").trim()) {
|
|
2739
|
-
return { attempted: false, started: false, reason: "telegram-not-ready" };
|
|
2741
|
+
return { attempted: false, started: false, reason: "telegram-not-ready", child: null };
|
|
2740
2742
|
}
|
|
2741
2743
|
|
|
2742
2744
|
const processInfo = await loadGatewayProcessInfo("telegram");
|
|
2743
2745
|
if (isProcessAlive(processInfo.pid)) {
|
|
2744
|
-
return { attempted: true, started: false, reason: "already-running", pid: processInfo.pid };
|
|
2746
|
+
return { attempted: true, started: false, reason: "already-running", pid: processInfo.pid, child: null };
|
|
2745
2747
|
}
|
|
2746
2748
|
|
|
2747
2749
|
const child = spawn(process.execPath, [BIN_PATH, "gateway", "run", "telegram", "--skip-onboarding"], {
|
|
2748
2750
|
cwd,
|
|
2749
|
-
detached: true,
|
|
2750
2751
|
stdio: "ignore",
|
|
2751
2752
|
env: {
|
|
2752
2753
|
...process.env,
|
|
@@ -2762,7 +2763,50 @@ async function maybeAutostartGateway(runtime, { cwd, io = console } = {}) {
|
|
|
2762
2763
|
});
|
|
2763
2764
|
|
|
2764
2765
|
io.log?.(dim(`telegram gateway autostarted in background (pid ${child.pid})`));
|
|
2765
|
-
return { attempted: true, started: true, pid: child.pid };
|
|
2766
|
+
return { attempted: true, started: true, pid: child.pid, child };
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
async function stopManagedGateway(service, gatewayHandle, { io = console } = {}) {
|
|
2770
|
+
const pid = Number(gatewayHandle?.pid || 0);
|
|
2771
|
+
if (!Number.isFinite(pid) || pid <= 0 || !isProcessAlive(pid)) {
|
|
2772
|
+
return false;
|
|
2773
|
+
}
|
|
2774
|
+
try {
|
|
2775
|
+
process.kill(pid, "SIGTERM");
|
|
2776
|
+
} catch {
|
|
2777
|
+
return false;
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
const deadline = Date.now() + 2500;
|
|
2781
|
+
while (Date.now() < deadline) {
|
|
2782
|
+
if (!isProcessAlive(pid)) {
|
|
2783
|
+
await saveGatewayProcessInfo(service, { pid: 0, startedAt: "", command: "" });
|
|
2784
|
+
return true;
|
|
2785
|
+
}
|
|
2786
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2789
|
+
try {
|
|
2790
|
+
process.kill(pid, "SIGKILL");
|
|
2791
|
+
} catch {}
|
|
2792
|
+
await saveGatewayProcessInfo(service, { pid: 0, startedAt: "", command: "" });
|
|
2793
|
+
io.log?.(dim(`${service} gateway forced down on TUI exit`));
|
|
2794
|
+
return true;
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2797
|
+
async function stopTrackedGateway(service = "telegram", { io = console } = {}) {
|
|
2798
|
+
const normalized = String(service || "telegram").trim().toLowerCase();
|
|
2799
|
+
if (normalized !== "telegram") {
|
|
2800
|
+
throw new Error("Usage: waterbrother gateway stop [telegram]");
|
|
2801
|
+
}
|
|
2802
|
+
const processInfo = await loadGatewayProcessInfo(normalized);
|
|
2803
|
+
const pid = Number(processInfo?.pid || 0);
|
|
2804
|
+
if (!Number.isFinite(pid) || pid <= 0 || !isProcessAlive(pid)) {
|
|
2805
|
+
await saveGatewayProcessInfo(normalized, { pid: 0, startedAt: "", command: "" });
|
|
2806
|
+
return { stopped: false, pid: 0 };
|
|
2807
|
+
}
|
|
2808
|
+
const stopped = await stopManagedGateway(normalized, { pid }, { io });
|
|
2809
|
+
return { stopped, pid };
|
|
2766
2810
|
}
|
|
2767
2811
|
|
|
2768
2812
|
async function chooseFromInteractiveMenu({ title, options, defaultIndex = 0 }) {
|
|
@@ -3533,7 +3577,20 @@ async function runGatewayCommand(positional, runtime, { cwd = process.cwd(), asJ
|
|
|
3533
3577
|
return;
|
|
3534
3578
|
}
|
|
3535
3579
|
|
|
3536
|
-
|
|
3580
|
+
if (sub === "stop") {
|
|
3581
|
+
const service = String(positional[2] || "telegram").trim().toLowerCase();
|
|
3582
|
+
const result = await stopTrackedGateway(service, { io: console });
|
|
3583
|
+
if (asJson) {
|
|
3584
|
+
printData({ ok: true, service, stopped: result.stopped, pid: result.pid }, true);
|
|
3585
|
+
} else if (result.stopped) {
|
|
3586
|
+
console.log(`Stopped ${service} gateway process ${result.pid}`);
|
|
3587
|
+
} else {
|
|
3588
|
+
console.log(`No running ${service} gateway process found`);
|
|
3589
|
+
}
|
|
3590
|
+
return;
|
|
3591
|
+
}
|
|
3592
|
+
|
|
3593
|
+
throw new Error("Usage: waterbrother gateway status|run <telegram>|stop [telegram]|pairings [telegram]|pair [telegram] <user-id>|unpair [telegram] <user-id>");
|
|
3537
3594
|
}
|
|
3538
3595
|
|
|
3539
3596
|
async function runMcpCommand(positional, runtime, { cwd, asJson = false } = {}) {
|
|
@@ -6534,7 +6591,30 @@ Be concrete about surfaces — name actual pages/flows. Choose the best stack fo
|
|
|
6534
6591
|
}
|
|
6535
6592
|
}
|
|
6536
6593
|
|
|
6537
|
-
await maybeAutostartGateway(context.runtime, { cwd: context.cwd });
|
|
6594
|
+
const gatewayHandle = await maybeAutostartGateway(context.runtime, { cwd: context.cwd });
|
|
6595
|
+
let gatewayCleanupDone = false;
|
|
6596
|
+
const cleanupManagedGateway = async () => {
|
|
6597
|
+
if (gatewayCleanupDone) return;
|
|
6598
|
+
gatewayCleanupDone = true;
|
|
6599
|
+
if (gatewayHandle?.started && gatewayHandle?.child) {
|
|
6600
|
+
await stopManagedGateway("telegram", gatewayHandle, { io: console });
|
|
6601
|
+
}
|
|
6602
|
+
};
|
|
6603
|
+
const cleanupManagedGatewaySync = () => {
|
|
6604
|
+
if (gatewayCleanupDone) return;
|
|
6605
|
+
gatewayCleanupDone = true;
|
|
6606
|
+
const pid = Number(gatewayHandle?.pid || 0);
|
|
6607
|
+
if (Number.isFinite(pid) && pid > 0 && isProcessAlive(pid)) {
|
|
6608
|
+
try {
|
|
6609
|
+
process.kill(pid, "SIGTERM");
|
|
6610
|
+
} catch {}
|
|
6611
|
+
}
|
|
6612
|
+
};
|
|
6613
|
+
const handleExitSignal = () => {
|
|
6614
|
+
cleanupManagedGatewaySync();
|
|
6615
|
+
};
|
|
6616
|
+
process.once("SIGINT", handleExitSignal);
|
|
6617
|
+
process.once("SIGTERM", handleExitSignal);
|
|
6538
6618
|
printInteractiveHeader({ runtime: context.runtime, agent, cwd: context.cwd });
|
|
6539
6619
|
console.log("Interactive mode. Type /exit to quit, /help for commands.");
|
|
6540
6620
|
if (process.stdout.isTTY) {
|
|
@@ -7148,6 +7228,20 @@ Be concrete about surfaces — name actual pages/flows. Choose the best stack fo
|
|
|
7148
7228
|
continue;
|
|
7149
7229
|
}
|
|
7150
7230
|
|
|
7231
|
+
if (line === "/gateway stop") {
|
|
7232
|
+
try {
|
|
7233
|
+
const result = await stopTrackedGateway("telegram", { io: console });
|
|
7234
|
+
if (result.stopped) {
|
|
7235
|
+
console.log(`Stopped telegram gateway process ${result.pid}`);
|
|
7236
|
+
} else {
|
|
7237
|
+
console.log("No running telegram gateway process found");
|
|
7238
|
+
}
|
|
7239
|
+
} catch (error) {
|
|
7240
|
+
console.log(`gateway stop failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
7241
|
+
}
|
|
7242
|
+
continue;
|
|
7243
|
+
}
|
|
7244
|
+
|
|
7151
7245
|
if (line === "/channels") {
|
|
7152
7246
|
for (const status of getChannelStatuses(context.runtime)) {
|
|
7153
7247
|
console.log(formatChannelStatusLine(status));
|
|
@@ -8808,6 +8902,10 @@ Be concrete about surfaces — name actual pages/flows. Choose the best stack fo
|
|
|
8808
8902
|
}
|
|
8809
8903
|
}
|
|
8810
8904
|
|
|
8905
|
+
await cleanupManagedGateway();
|
|
8906
|
+
process.off("SIGINT", handleExitSignal);
|
|
8907
|
+
process.off("SIGTERM", handleExitSignal);
|
|
8908
|
+
|
|
8811
8909
|
// Kill any running preview server
|
|
8812
8910
|
killPreview();
|
|
8813
8911
|
|