From 48ad3bbbe6e5db4e4793c64d2125bc2344837be4 Mon Sep 17 00:00:00 2001 From: Azade Date: Sat, 10 Jan 2026 15:54:03 +0000 Subject: [PATCH 1/2] fix: use resolveStateDir() for node-pairing and voicewake storage Both node-pairing.ts and voicewake.ts were using a local defaultBaseDir() that hardcoded ~/.clawdbot, ignoring CLAWDBOT_STATE_DIR. This caused nodes/paired.json and settings/voicewake.json to be stored in ~/.clawdbot instead of the configured state directory. Fixes the bug where paired nodes config was stored in a different location than the rest of the gateway state. --- src/infra/node-pairing.ts | 8 ++------ src/infra/voicewake.ts | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/infra/node-pairing.ts b/src/infra/node-pairing.ts index e98a2b556..4c762b023 100644 --- a/src/infra/node-pairing.ts +++ b/src/infra/node-pairing.ts @@ -1,7 +1,7 @@ import { randomUUID } from "node:crypto"; import fs from "node:fs/promises"; -import os from "node:os"; import path from "node:path"; +import { resolveStateDir } from "../config/paths.js"; export type NodePairingPendingRequest = { requestId: string; @@ -48,12 +48,8 @@ type NodePairingStateFile = { const PENDING_TTL_MS = 5 * 60 * 1000; -function defaultBaseDir() { - return path.join(os.homedir(), ".clawdbot"); -} - function resolvePaths(baseDir?: string) { - const root = baseDir ?? defaultBaseDir(); + const root = baseDir ?? resolveStateDir(); const dir = path.join(root, "nodes"); return { dir, diff --git a/src/infra/voicewake.ts b/src/infra/voicewake.ts index 379c634b0..6ffb3c53f 100644 --- a/src/infra/voicewake.ts +++ b/src/infra/voicewake.ts @@ -1,7 +1,7 @@ import { randomUUID } from "node:crypto"; import fs from "node:fs/promises"; -import os from "node:os"; import path from "node:path"; +import { resolveStateDir } from "../config/paths.js"; export type VoiceWakeConfig = { triggers: string[]; @@ -10,12 +10,8 @@ export type VoiceWakeConfig = { const DEFAULT_TRIGGERS = ["clawd", "claude", "computer"]; -function defaultBaseDir() { - return path.join(os.homedir(), ".clawdbot"); -} - function resolvePath(baseDir?: string) { - const root = baseDir ?? defaultBaseDir(); + const root = baseDir ?? resolveStateDir(); return path.join(root, "settings", "voicewake.json"); } From 464f0645a8bd107ad8b806dda5ca3a28915a8b52 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 10 Jan 2026 18:06:05 +0100 Subject: [PATCH 2/2] fix: stabilize telegram media tests (#664) (thanks @azade-c) --- CHANGELOG.md | 1 + src/telegram/bot.media.test.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c0f45586..43ef36ff3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Agents/OpenAI: fix Responses tool-only → follow-up turn handling (avoid standalone `reasoning` items that trigger 400 “required following item”). - Auth: update Claude Code keychain credentials in-place during refresh sync; share JSON file helpers; add CLI fallback coverage. - Auth: throttle external CLI credential syncs (Claude/Codex), reduce Keychain reads, and skip sync when cached credentials are still fresh. +- CLI: respect `CLAWDBOT_STATE_DIR` for node pairing + voice wake settings storage. (#664) — thanks @azade-c. - Onboarding/Gateway: persist non-interactive gateway token auth in config; add WS wizard + gateway tool-calling regression coverage. - Gateway/Control UI: make `chat.send` non-blocking, wire Stop to `chat.abort`, and treat `/stop` as an out-of-band abort. (#653) - Gateway/Control UI: allow `chat.abort` without `runId` (abort active runs), suppress post-abort chat streaming, and prune stuck chat runs. (#653) diff --git a/src/telegram/bot.media.test.ts b/src/telegram/bot.media.test.ts index e0ec45a2c..a30c10d8d 100644 --- a/src/telegram/bot.media.test.ts +++ b/src/telegram/bot.media.test.ts @@ -45,6 +45,14 @@ vi.mock("../config/config.js", async (importOriginal) => { }; }); +vi.mock("../config/sessions.js", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + updateLastRoute: vi.fn(async () => undefined), + }; +}); + vi.mock("./pairing-store.js", () => ({ readTelegramAllowFromStore: vi.fn(async () => [] as string[]), upsertTelegramPairingRequest: vi.fn(async () => ({ @@ -63,7 +71,7 @@ vi.mock("../auto-reply/reply.js", () => { describe("telegram inbound media", () => { const INBOUND_MEDIA_TEST_TIMEOUT_MS = - process.platform === "win32" ? 30_000 : 10_000; + process.platform === "win32" ? 30_000 : 20_000; it( "downloads media via file_path (no file.download)",