mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 12:40:43 +00:00
feat(cli/logs): announce --follow gateway reconnect and add JSON notice parity (#75372)
This commit is contained in:
@@ -369,10 +369,52 @@ describe("logs cli", () => {
|
||||
|
||||
expect(readConfiguredLogTail).not.toHaveBeenCalled();
|
||||
expect(stderrWrites.join("")).toContain("gateway disconnected");
|
||||
expect(stderrWrites.join("")).toContain("gateway reconnected");
|
||||
expect(stdoutWrites.join("")).toContain("line from remote");
|
||||
expect(exitSpy).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it("emits notice JSON records for retry and reconnect in --follow --json mode", async () => {
|
||||
callGatewayFromCli
|
||||
.mockRejectedValueOnce(
|
||||
new GatewayTransportError({
|
||||
kind: "closed",
|
||||
code: 1006,
|
||||
reason: "abnormal closure",
|
||||
connectionDetails: {
|
||||
url: "ws://remote.example.com:18789",
|
||||
urlSource: "cli",
|
||||
message: "",
|
||||
},
|
||||
message: "gateway closed (1006 abnormal closure): abnormal closure",
|
||||
}),
|
||||
)
|
||||
.mockResolvedValueOnce({
|
||||
file: "/tmp/openclaw.log",
|
||||
cursor: 10,
|
||||
lines: [],
|
||||
});
|
||||
|
||||
const stderrWrites = captureStderrWrites();
|
||||
const stdoutWrites = captureStdoutWrites();
|
||||
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => undefined as never);
|
||||
|
||||
await runLogsCli(["logs", "--follow", "--json", "--url", "ws://remote.example.com:18789"]);
|
||||
|
||||
const stderr = stderrWrites.join("");
|
||||
const noticeRecords = stderr
|
||||
.split("\n")
|
||||
.filter((line) => line.length > 0)
|
||||
.map((line) => JSON.parse(line) as { type: string; message?: string });
|
||||
const messages = noticeRecords
|
||||
.filter((record) => record.type === "notice")
|
||||
.map((record) => record.message ?? "");
|
||||
expect(messages.some((message) => message.includes("gateway disconnected"))).toBe(true);
|
||||
expect(messages.some((message) => message.includes("gateway reconnected"))).toBe(true);
|
||||
expect(stdoutWrites.join("")).toContain('"type":"meta"');
|
||||
expect(exitSpy).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it("exits immediately on pairing-required close errors in --follow mode with explicit URL", async () => {
|
||||
callGatewayFromCli.mockRejectedValueOnce(
|
||||
new GatewayTransportError({
|
||||
|
||||
@@ -341,15 +341,12 @@ export function registerLogsCli(program: Command) {
|
||||
if (opts.follow && followRetryAttempt < MAX_FOLLOW_RETRIES && isTransientFollowError(err)) {
|
||||
followRetryAttempt += 1;
|
||||
const backoffMs = computeBackoff(FOLLOW_BACKOFF_POLICY, followRetryAttempt);
|
||||
if (
|
||||
!errorLine(
|
||||
colorize(
|
||||
rich,
|
||||
theme.warn,
|
||||
`[logs] gateway disconnected, reconnecting in ${Math.round(backoffMs / 1_000)}s...`,
|
||||
),
|
||||
)
|
||||
) {
|
||||
const message = `[logs] gateway disconnected, reconnecting in ${Math.round(backoffMs / 1_000)}s...`;
|
||||
if (jsonMode) {
|
||||
if (!emitJsonLine({ type: "notice", message }, true)) {
|
||||
return;
|
||||
}
|
||||
} else if (!errorLine(colorize(rich, theme.warn, message))) {
|
||||
return;
|
||||
}
|
||||
await delay(backoffMs);
|
||||
@@ -366,6 +363,16 @@ export function registerLogsCli(program: Command) {
|
||||
process.exit(1);
|
||||
return;
|
||||
}
|
||||
if (followRetryAttempt > 0) {
|
||||
const message = "[logs] gateway reconnected";
|
||||
if (jsonMode) {
|
||||
if (!emitJsonLine({ type: "notice", message }, true)) {
|
||||
return;
|
||||
}
|
||||
} else if (!errorLine(colorize(rich, theme.muted, message))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
followRetryAttempt = 0;
|
||||
const lines = Array.isArray(payload.lines) ? payload.lines : [];
|
||||
if (jsonMode) {
|
||||
|
||||
Reference in New Issue
Block a user