refactor: use subsystem logger in workspace-sync handler
This commit is contained in:
parent
0d8c321d45
commit
5bdcbc7e32
@ -1,8 +1,23 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
import workspaceSyncHandler from "./handler.js";
|
|
||||||
import * as rclone from "../../../infra/rclone.js";
|
import * as rclone from "../../../infra/rclone.js";
|
||||||
|
|
||||||
|
const mockLog = vi.hoisted(() => ({
|
||||||
|
info: vi.fn(),
|
||||||
|
warn: vi.fn(),
|
||||||
|
error: vi.fn(),
|
||||||
|
debug: vi.fn(),
|
||||||
|
trace: vi.fn(),
|
||||||
|
fatal: vi.fn(),
|
||||||
|
raw: vi.fn(),
|
||||||
|
child: vi.fn(),
|
||||||
|
subsystem: "workspace-sync",
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("../../../logging/subsystem.js", () => ({
|
||||||
|
createSubsystemLogger: vi.fn(() => mockLog),
|
||||||
|
}));
|
||||||
|
|
||||||
vi.mock("../../../infra/rclone.js", () => ({
|
vi.mock("../../../infra/rclone.js", () => ({
|
||||||
isRcloneInstalled: vi.fn(),
|
isRcloneInstalled: vi.fn(),
|
||||||
isRcloneConfigured: vi.fn(),
|
isRcloneConfigured: vi.fn(),
|
||||||
@ -18,6 +33,9 @@ vi.mock("../../../routing/session-key.js", () => ({
|
|||||||
resolveAgentIdFromSessionKey: vi.fn(() => "default"),
|
resolveAgentIdFromSessionKey: vi.fn(() => "default"),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Import after mocks are set up
|
||||||
|
const { default: workspaceSyncHandler } = await import("./handler.js");
|
||||||
|
|
||||||
describe("workspace-sync hook handler", () => {
|
describe("workspace-sync hook handler", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
@ -126,7 +144,6 @@ describe("workspace-sync hook handler", () => {
|
|||||||
|
|
||||||
it("warns when rclone is not installed", async () => {
|
it("warns when rclone is not installed", async () => {
|
||||||
vi.mocked(rclone.isRcloneInstalled).mockResolvedValue(false);
|
vi.mocked(rclone.isRcloneInstalled).mockResolvedValue(false);
|
||||||
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
||||||
|
|
||||||
const event = {
|
const event = {
|
||||||
type: "session",
|
type: "session",
|
||||||
@ -148,7 +165,7 @@ describe("workspace-sync hook handler", () => {
|
|||||||
await workspaceSyncHandler(event as never);
|
await workspaceSyncHandler(event as never);
|
||||||
|
|
||||||
expect(rclone.isRcloneInstalled).toHaveBeenCalled();
|
expect(rclone.isRcloneInstalled).toHaveBeenCalled();
|
||||||
expect(warnSpy).toHaveBeenCalledWith("[workspace-sync] rclone not installed, skipping sync");
|
expect(mockLog.warn).toHaveBeenCalledWith("rclone not installed, skipping sync");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("warns when rclone is not configured", async () => {
|
it("warns when rclone is not configured", async () => {
|
||||||
@ -166,7 +183,6 @@ describe("workspace-sync hook handler", () => {
|
|||||||
onSessionStart: true,
|
onSessionStart: true,
|
||||||
onSessionEnd: false,
|
onSessionEnd: false,
|
||||||
});
|
});
|
||||||
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
||||||
|
|
||||||
const event = {
|
const event = {
|
||||||
type: "session",
|
type: "session",
|
||||||
@ -187,7 +203,7 @@ describe("workspace-sync hook handler", () => {
|
|||||||
|
|
||||||
await workspaceSyncHandler(event as never);
|
await workspaceSyncHandler(event as never);
|
||||||
|
|
||||||
expect(warnSpy).toHaveBeenCalledWith(
|
expect(mockLog.warn).toHaveBeenCalledWith(
|
||||||
expect.stringContaining('rclone not configured for remote "cloud"'),
|
expect.stringContaining('rclone not configured for remote "cloud"'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -208,7 +224,6 @@ describe("workspace-sync hook handler", () => {
|
|||||||
onSessionEnd: false,
|
onSessionEnd: false,
|
||||||
});
|
});
|
||||||
vi.mocked(rclone.runBisync).mockResolvedValue({ ok: true });
|
vi.mocked(rclone.runBisync).mockResolvedValue({ ok: true });
|
||||||
vi.spyOn(console, "log").mockImplementation(() => {});
|
|
||||||
|
|
||||||
const event = {
|
const event = {
|
||||||
type: "session",
|
type: "session",
|
||||||
@ -255,7 +270,6 @@ describe("workspace-sync hook handler", () => {
|
|||||||
onSessionEnd: true,
|
onSessionEnd: true,
|
||||||
});
|
});
|
||||||
vi.mocked(rclone.runBisync).mockResolvedValue({ ok: true });
|
vi.mocked(rclone.runBisync).mockResolvedValue({ ok: true });
|
||||||
vi.spyOn(console, "log").mockImplementation(() => {});
|
|
||||||
|
|
||||||
const event = {
|
const event = {
|
||||||
type: "session",
|
type: "session",
|
||||||
@ -298,8 +312,6 @@ describe("workspace-sync hook handler", () => {
|
|||||||
ok: false,
|
ok: false,
|
||||||
error: "bisync requires --resync on first run",
|
error: "bisync requires --resync on first run",
|
||||||
});
|
});
|
||||||
vi.spyOn(console, "log").mockImplementation(() => {});
|
|
||||||
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
||||||
|
|
||||||
const event = {
|
const event = {
|
||||||
type: "session",
|
type: "session",
|
||||||
@ -320,8 +332,8 @@ describe("workspace-sync hook handler", () => {
|
|||||||
|
|
||||||
await workspaceSyncHandler(event as never);
|
await workspaceSyncHandler(event as never);
|
||||||
|
|
||||||
expect(warnSpy).toHaveBeenCalledWith(
|
expect(mockLog.warn).toHaveBeenCalledWith(
|
||||||
expect.stringContaining("First sync requires manual --resync"),
|
expect.stringContaining("first sync requires manual --resync"),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
import type { MoltbotConfig } from "../../../config/config.js";
|
import type { MoltbotConfig } from "../../../config/config.js";
|
||||||
import { resolveAgentWorkspaceDir } from "../../../agents/agent-scope.js";
|
import { resolveAgentWorkspaceDir } from "../../../agents/agent-scope.js";
|
||||||
import { resolveAgentIdFromSessionKey } from "../../../routing/session-key.js";
|
import { resolveAgentIdFromSessionKey } from "../../../routing/session-key.js";
|
||||||
|
import { createSubsystemLogger } from "../../../logging/subsystem.js";
|
||||||
import type { HookHandler } from "../../hooks.js";
|
import type { HookHandler } from "../../hooks.js";
|
||||||
import {
|
import {
|
||||||
isRcloneInstalled,
|
isRcloneInstalled,
|
||||||
@ -16,6 +17,8 @@ import {
|
|||||||
runBisync,
|
runBisync,
|
||||||
} from "../../../infra/rclone.js";
|
} from "../../../infra/rclone.js";
|
||||||
|
|
||||||
|
const log = createSubsystemLogger("workspace-sync");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync workspace on session start or end
|
* Sync workspace on session start or end
|
||||||
*/
|
*/
|
||||||
@ -55,13 +58,13 @@ const workspaceSyncHandler: HookHandler = async (event) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[workspace-sync] Triggered on session ${event.action}`);
|
log.info(`triggered on session ${event.action}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if rclone is installed
|
// Check if rclone is installed
|
||||||
const installed = await isRcloneInstalled();
|
const installed = await isRcloneInstalled();
|
||||||
if (!installed) {
|
if (!installed) {
|
||||||
console.warn("[workspace-sync] rclone not installed, skipping sync");
|
log.warn("rclone not installed, skipping sync");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,15 +77,11 @@ const workspaceSyncHandler: HookHandler = async (event) => {
|
|||||||
|
|
||||||
// Check if rclone is configured
|
// Check if rclone is configured
|
||||||
if (!isRcloneConfigured(resolved.configPath, resolved.remoteName)) {
|
if (!isRcloneConfigured(resolved.configPath, resolved.remoteName)) {
|
||||||
console.warn(
|
log.warn(`rclone not configured for remote "${resolved.remoteName}", skipping sync`);
|
||||||
`[workspace-sync] rclone not configured for remote "${resolved.remoteName}", skipping sync`,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(
|
log.info(`syncing ${resolved.remoteName}:${resolved.remotePath} <-> ${resolved.localPath}`);
|
||||||
`[workspace-sync] Syncing ${resolved.remoteName}:${resolved.remotePath} <-> ${resolved.localPath}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Run sync
|
// Run sync
|
||||||
const result = await runBisync({
|
const result = await runBisync({
|
||||||
@ -96,22 +95,20 @@ const workspaceSyncHandler: HookHandler = async (event) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (result.ok) {
|
if (result.ok) {
|
||||||
console.log("[workspace-sync] Sync completed successfully");
|
log.info("sync completed successfully");
|
||||||
if (result.filesTransferred) {
|
if (result.filesTransferred) {
|
||||||
console.log(`[workspace-sync] Files transferred: ${result.filesTransferred}`);
|
log.info(`files transferred: ${result.filesTransferred}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check if this is a first-run issue
|
// Check if this is a first-run issue
|
||||||
if (result.error?.includes("--resync")) {
|
if (result.error?.includes("--resync")) {
|
||||||
console.warn(
|
log.warn("first sync requires manual --resync. Run: moltbot workspace sync --resync");
|
||||||
"[workspace-sync] First sync requires manual --resync. Run: moltbot workspace sync --resync",
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
console.error(`[workspace-sync] Sync failed: ${result.error}`);
|
log.error(`sync failed: ${result.error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("[workspace-sync] Error:", err instanceof Error ? err.message : String(err));
|
log.error(`error: ${err instanceof Error ? err.message : String(err)}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user