diff --git a/Dockerfile b/Dockerfile index 9ddf13127..8dd06d8bf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,10 +8,10 @@ RUN corepack enable WORKDIR /app -ARG CLAWDBOT_DOCKER_APT_PACKAGES="" -RUN if [ -n "$CLAWDBOT_DOCKER_APT_PACKAGES" ]; then \ +ARG MOLTBOT_DOCKER_APT_PACKAGES="" +RUN if [ -n "$MOLTBOT_DOCKER_APT_PACKAGES" ]; then \ apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $CLAWDBOT_DOCKER_APT_PACKAGES && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $MOLTBOT_DOCKER_APT_PACKAGES && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*; \ fi @@ -28,7 +28,7 @@ RUN pnpm install --frozen-lockfile COPY . . RUN pnpm build # Force pnpm for UI build (Bun may fail on ARM/Synology architectures) -ENV CLAWDBOT_PREFER_PNPM=1 +ENV MOLTBOT_PREFER_PNPM=1 RUN pnpm ui:install RUN pnpm ui:build diff --git a/package.json b/package.json index 0c63d5d69..5b415ed0f 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "clawdbot", + "name": "moltbot", "version": "2026.1.25", "description": "WhatsApp gateway CLI (Baileys web) with Pi RPC agent", "type": "module", @@ -10,6 +10,7 @@ "./plugin-sdk/*": "./dist/plugin-sdk/*" }, "bin": { + "moltbot": "dist/entry.js", "clawdbot": "dist/entry.js" }, "files": [ diff --git a/render.yaml b/render.yaml index 5131b3469..dd0ff11f6 100644 --- a/render.yaml +++ b/render.yaml @@ -1,6 +1,6 @@ services: - type: web - name: clawdbot + name: moltbot runtime: docker plan: starter dockerCommand: /bin/sh scripts/render-start.sh @@ -34,6 +34,6 @@ services: - key: DEEPGRAM_API_KEY sync: false disk: - name: clawdbot-data + name: moltbot-data mountPath: /data sizeGB: 1 diff --git a/scripts/render-start.sh b/scripts/render-start.sh index b65674ebc..6960773d1 100755 --- a/scripts/render-start.sh +++ b/scripts/render-start.sh @@ -5,6 +5,7 @@ echo "=== Render startup script ===" echo "HOME=${HOME:-not set}" echo "CLAWDBOT_STATE_DIR=${CLAWDBOT_STATE_DIR:-not set}" +echo "MOLTBOT_STATE_DIR=${MOLTBOT_STATE_DIR:-not set}" echo "User: $(whoami 2>/dev/null || echo unknown)" echo "UID: $(id -u 2>/dev/null || echo unknown)" echo "PWD: $(pwd)" @@ -19,29 +20,30 @@ if [ -z "${HOME}" ]; then echo "Set HOME to: ${HOME}" fi -# Use CLAWDBOT_STATE_DIR if set and writable, otherwise use HOME/.clawdbot -CONFIG_DIR="${HOME}/.clawdbot" -if [ -n "${CLAWDBOT_STATE_DIR}" ]; then - # Test if we can write to it (disable exit on error for this test) - set +e - mkdir -p "${CLAWDBOT_STATE_DIR}" 2>/dev/null - touch "${CLAWDBOT_STATE_DIR}/.test" 2>/dev/null - if [ $? -eq 0 ]; then - rm -f "${CLAWDBOT_STATE_DIR}/.test" 2>/dev/null - CONFIG_DIR="${CLAWDBOT_STATE_DIR}" - echo "Using CLAWDBOT_STATE_DIR: ${CONFIG_DIR}" - else - echo "Warning: ${CLAWDBOT_STATE_DIR} not writable, using ${CONFIG_DIR}" +# Prefer MOLTBOT_STATE_DIR or CLAWDBOT_STATE_DIR (legacy), else HOME/.moltbot then HOME/.clawdbot +CONFIG_DIR="${HOME}/.moltbot" +for var in MOLTBOT_STATE_DIR CLAWDBOT_STATE_DIR; do + eval "val=\${${var}:-}" + if [ -n "$val" ]; then + set +e + mkdir -p "$val" 2>/dev/null + touch "$val/.test" 2>/dev/null + if [ $? -eq 0 ]; then + rm -f "$val/.test" 2>/dev/null + CONFIG_DIR="$val" + echo "Using ${var}: ${CONFIG_DIR}" + fi + set -e + break fi - set -e -fi +done -CONFIG_FILE="${CONFIG_DIR}/clawdbot.json" +CONFIG_FILE="${CONFIG_DIR}/moltbot.json" echo "Config dir: ${CONFIG_DIR}" echo "Config file: ${CONFIG_FILE}" -# Create config directory (this should always work for HOME/.clawdbot) +# Create config directory (fallback: HOME/.moltbot or HOME/.clawdbot) if ! mkdir -p "${CONFIG_DIR}" 2>/dev/null; then echo "ERROR: Failed to create config directory: ${CONFIG_DIR}" exit 1 @@ -73,14 +75,17 @@ if [ ! -f "${CONFIG_FILE}" ]; then exit 1 fi -# Set environment variables for gateway +# Set environment variables for gateway (app accepts MOLTBOT_* or CLAWDBOT_*) export CLAWDBOT_STATE_DIR="${CONFIG_DIR}" export CLAWDBOT_CONFIG_PATH="${CONFIG_FILE}" export CLAWDBOT_CONFIG_CACHE_MS=0 +export MOLTBOT_STATE_DIR="${CONFIG_DIR}" +export MOLTBOT_CONFIG_PATH="${CONFIG_FILE}" +export MOLTBOT_CONFIG_CACHE_MS=0 echo "=== Starting gateway ===" -echo "CLAWDBOT_STATE_DIR=${CLAWDBOT_STATE_DIR}" -echo "CLAWDBOT_CONFIG_PATH=${CLAWDBOT_CONFIG_PATH}" +echo "CONFIG_DIR=${CONFIG_DIR}" +echo "CONFIG_FILE=${CONFIG_FILE}" # Verify node is available if ! command -v node >/dev/null 2>&1; then @@ -103,13 +108,14 @@ fi echo "Found dist/index.js" -# Check if token is set -if [ -z "${CLAWDBOT_GATEWAY_TOKEN}" ]; then - echo "ERROR: CLAWDBOT_GATEWAY_TOKEN is not set" +# Token: CLAWDBOT_GATEWAY_TOKEN (legacy) or MOLTBOT_GATEWAY_TOKEN +GATEWAY_TOKEN="${CLAWDBOT_GATEWAY_TOKEN:-${MOLTBOT_GATEWAY_TOKEN}}" +if [ -z "${GATEWAY_TOKEN}" ]; then + echo "ERROR: CLAWDBOT_GATEWAY_TOKEN or MOLTBOT_GATEWAY_TOKEN must be set" exit 1 fi -echo "Token is set (length: ${#CLAWDBOT_GATEWAY_TOKEN})" +echo "Token is set (length: ${#GATEWAY_TOKEN})" # Enable strict error handling for the final exec set -e @@ -120,5 +126,5 @@ exec node dist/index.js gateway \ --port 8080 \ --bind lan \ --auth token \ - --token "${CLAWDBOT_GATEWAY_TOKEN}" \ + --token "${GATEWAY_TOKEN}" \ --allow-unconfigured diff --git a/src/agents/sandbox/constants.ts b/src/agents/sandbox/constants.ts index c6391789a..b53945e5e 100644 --- a/src/agents/sandbox/constants.ts +++ b/src/agents/sandbox/constants.ts @@ -2,9 +2,9 @@ import os from "node:os"; import path from "node:path"; import { CHANNEL_IDS } from "../../channels/registry.js"; -import { STATE_DIR_CLAWDBOT } from "../../config/config.js"; +import { STATE_DIR_MOLTBOT } from "../../config/config.js"; -export const DEFAULT_SANDBOX_WORKSPACE_ROOT = path.join(os.homedir(), ".clawdbot", "sandboxes"); +export const DEFAULT_SANDBOX_WORKSPACE_ROOT = path.join(os.homedir(), ".moltbot", "sandboxes"); export const DEFAULT_SANDBOX_IMAGE = "clawdbot-sandbox:bookworm-slim"; export const DEFAULT_SANDBOX_CONTAINER_PREFIX = "clawdbot-sbx-"; @@ -48,7 +48,7 @@ export const DEFAULT_SANDBOX_BROWSER_AUTOSTART_TIMEOUT_MS = 12_000; export const SANDBOX_AGENT_WORKSPACE_MOUNT = "/agent"; -const resolvedSandboxStateDir = STATE_DIR_CLAWDBOT ?? path.join(os.homedir(), ".clawdbot"); +const resolvedSandboxStateDir = STATE_DIR_MOLTBOT ?? path.join(os.homedir(), ".moltbot"); export const SANDBOX_STATE_DIR = path.join(resolvedSandboxStateDir, "sandbox"); export const SANDBOX_REGISTRY_PATH = path.join(SANDBOX_STATE_DIR, "containers.json"); export const SANDBOX_BROWSER_REGISTRY_PATH = path.join(SANDBOX_STATE_DIR, "browsers.json"); diff --git a/src/agents/subagent-registry.store.ts b/src/agents/subagent-registry.store.ts index ceac23156..3dab0a60e 100644 --- a/src/agents/subagent-registry.store.ts +++ b/src/agents/subagent-registry.store.ts @@ -1,6 +1,6 @@ import path from "node:path"; -import { STATE_DIR_CLAWDBOT } from "../config/paths.js"; +import { STATE_DIR_MOLTBOT } from "../config/paths.js"; import { loadJsonFile, saveJsonFile } from "../infra/json-file.js"; import { normalizeDeliveryContext } from "../utils/delivery-context.js"; import type { SubagentRunRecord } from "./subagent-registry.js"; @@ -31,7 +31,7 @@ type LegacySubagentRunRecord = PersistedSubagentRunRecord & { }; export function resolveSubagentRegistryPath(): string { - return path.join(STATE_DIR_CLAWDBOT, "subagents", "runs.json"); + return path.join(STATE_DIR_MOLTBOT, "subagents", "runs.json"); } export function loadSubagentRegistryFromDisk(): Map { diff --git a/src/cli/browser-cli-extension.ts b/src/cli/browser-cli-extension.ts index 3bd7c5b3a..c4446e878 100644 --- a/src/cli/browser-cli-extension.ts +++ b/src/cli/browser-cli-extension.ts @@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url"; import type { Command } from "commander"; -import { STATE_DIR_CLAWDBOT } from "../config/paths.js"; +import { STATE_DIR_MOLTBOT } from "../config/paths.js"; import { danger, info } from "../globals.js"; import { copyToClipboard } from "../infra/clipboard.js"; import { defaultRuntime } from "../runtime.js"; @@ -20,7 +20,7 @@ function bundledExtensionRootDir() { } function installedExtensionRootDir() { - return path.join(STATE_DIR_CLAWDBOT, "browser", "chrome-extension"); + return path.join(STATE_DIR_MOLTBOT, "browser", "chrome-extension"); } function hasManifest(dir: string) { @@ -36,7 +36,7 @@ export async function installChromeExtension(opts?: { throw new Error("Bundled Chrome extension is missing. Reinstall Clawdbot and try again."); } - const stateDir = opts?.stateDir ?? STATE_DIR_CLAWDBOT; + const stateDir = opts?.stateDir ?? STATE_DIR_MOLTBOT; const dest = path.join(stateDir, "browser", "chrome-extension"); fs.mkdirSync(path.dirname(dest), { recursive: true }); diff --git a/src/cli/gateway-cli/dev.ts b/src/cli/gateway-cli/dev.ts index f851beec3..652b12e4f 100644 --- a/src/cli/gateway-cli/dev.ts +++ b/src/cli/gateway-cli/dev.ts @@ -4,7 +4,7 @@ import path from "node:path"; import { resolveDefaultAgentWorkspaceDir } from "../../agents/workspace.js"; import { handleReset } from "../../commands/onboard-helpers.js"; -import { CONFIG_PATH_CLAWDBOT, writeConfigFile } from "../../config/config.js"; +import { CONFIG_PATH_MOLTBOT, writeConfigFile } from "../../config/config.js"; import { defaultRuntime } from "../../runtime.js"; import { resolveUserPath, shortenHomePath } from "../../utils.js"; @@ -89,7 +89,7 @@ export async function ensureDevGatewayConfig(opts: { reset?: boolean }) { await handleReset("full", workspace, defaultRuntime); } - const configExists = fs.existsSync(CONFIG_PATH_CLAWDBOT); + const configExists = fs.existsSync(CONFIG_PATH_MOLTBOT); if (!opts.reset && configExists) return; await writeConfigFile({ @@ -117,6 +117,6 @@ export async function ensureDevGatewayConfig(opts: { reset?: boolean }) { }, }); await ensureDevWorkspace(workspace); - defaultRuntime.log(`Dev config ready: ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}`); + defaultRuntime.log(`Dev config ready: ${shortenHomePath(CONFIG_PATH_MOLTBOT)}`); defaultRuntime.log(`Dev workspace ready: ${shortenHomePath(resolveUserPath(workspace))}`); } diff --git a/src/cli/gateway-cli/run.ts b/src/cli/gateway-cli/run.ts index 0de667c3c..b1b972e67 100644 --- a/src/cli/gateway-cli/run.ts +++ b/src/cli/gateway-cli/run.ts @@ -3,7 +3,7 @@ import fs from "node:fs"; import type { Command } from "commander"; import type { GatewayAuthMode } from "../../config/config.js"; import { - CONFIG_PATH_CLAWDBOT, + CONFIG_PATH_MOLTBOT, loadConfig, readConfigFileSnapshot, resolveGatewayPort, @@ -157,7 +157,7 @@ async function runGatewayCommand(opts: GatewayRunOpts) { const passwordRaw = toOptionString(opts.password); const tokenRaw = toOptionString(opts.token); - const configExists = fs.existsSync(CONFIG_PATH_CLAWDBOT); + const configExists = fs.existsSync(CONFIG_PATH_MOLTBOT); const mode = cfg.gateway?.mode; if (!opts.allowUnconfigured && mode !== "local") { if (!configExists) { diff --git a/src/commands/configure.channels.ts b/src/commands/configure.channels.ts index 2eeba4aa2..e67fd40cc 100644 --- a/src/commands/configure.channels.ts +++ b/src/commands/configure.channels.ts @@ -1,7 +1,7 @@ import { getChannelPlugin, listChannelPlugins } from "../channels/plugins/index.js"; import { formatCliCommand } from "../cli/command-format.js"; import type { ClawdbotConfig } from "../config/config.js"; -import { CONFIG_PATH_CLAWDBOT } from "../config/config.js"; +import { CONFIG_PATH_MOLTBOT } from "../config/config.js"; import type { RuntimeEnv } from "../runtime.js"; import { note } from "../terminal/note.js"; import { shortenHomePath } from "../utils.js"; @@ -52,7 +52,7 @@ export async function removeChannelConfigWizard( const label = getChannelPlugin(channel)?.meta.label ?? channel; const confirmed = guardCancel( await confirm({ - message: `Delete ${label} configuration from ${shortenHomePath(CONFIG_PATH_CLAWDBOT)}?`, + message: `Delete ${label} configuration from ${shortenHomePath(CONFIG_PATH_MOLTBOT)}?`, initialValue: false, }), runtime, diff --git a/src/commands/configure.wizard.test.ts b/src/commands/configure.wizard.test.ts index 2fb68ebdc..8e6b95757 100644 --- a/src/commands/configure.wizard.test.ts +++ b/src/commands/configure.wizard.test.ts @@ -30,7 +30,7 @@ vi.mock("@clack/prompts", () => ({ })); vi.mock("../config/config.js", () => ({ - CONFIG_PATH_CLAWDBOT: "~/.clawdbot/clawdbot.json", + CONFIG_PATH_MOLTBOT: "~/.moltbot/moltbot.json", readConfigFileSnapshot: mocks.readConfigFileSnapshot, writeConfigFile: mocks.writeConfigFile, resolveGatewayPort: mocks.resolveGatewayPort, diff --git a/src/commands/doctor-config-flow.ts b/src/commands/doctor-config-flow.ts index a656c6368..3b891bf2e 100644 --- a/src/commands/doctor-config-flow.ts +++ b/src/commands/doctor-config-flow.ts @@ -3,7 +3,7 @@ import type { ZodIssue } from "zod"; import type { ClawdbotConfig } from "../config/config.js"; import { ClawdbotSchema, - CONFIG_PATH_CLAWDBOT, + CONFIG_PATH_MOLTBOT, migrateLegacyConfig, readConfigFileSnapshot, } from "../config/config.js"; @@ -214,5 +214,5 @@ export async function loadAndMaybeMigrateDoctorConfig(params: { noteOpencodeProviderOverrides(cfg); - return { cfg, path: snapshot.path ?? CONFIG_PATH_CLAWDBOT, shouldWriteConfig }; + return { cfg, path: snapshot.path ?? CONFIG_PATH_MOLTBOT, shouldWriteConfig }; } diff --git a/src/commands/doctor.falls-back-legacy-sandbox-image-missing.test.ts b/src/commands/doctor.falls-back-legacy-sandbox-image-missing.test.ts index 6d351b5ab..6237f22fb 100644 --- a/src/commands/doctor.falls-back-legacy-sandbox-image-missing.test.ts +++ b/src/commands/doctor.falls-back-legacy-sandbox-image-missing.test.ts @@ -34,7 +34,7 @@ beforeEach(() => { durationMs: 0, }); legacyReadConfigFileSnapshot.mockReset().mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: false, raw: null, parsed: {}, @@ -135,7 +135,7 @@ const ensureAuthProfileStore = vi.fn().mockReturnValue({ version: 1, profiles: { const loadClawdbotPlugins = vi.fn().mockReturnValue({ plugins: [], diagnostics: [] }); const legacyReadConfigFileSnapshot = vi.fn().mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: false, raw: null, parsed: {}, @@ -181,7 +181,7 @@ vi.mock("../config/config.js", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, - CONFIG_PATH_CLAWDBOT: "/tmp/clawdbot.json", + CONFIG_PATH_MOLTBOT: "/tmp/moltbot.json", createConfigIO, readConfigFileSnapshot, writeConfigFile, @@ -327,7 +327,7 @@ vi.mock("./doctor-state-migrations.js", () => ({ describe("doctor command", () => { it("runs legacy state migrations in non-interactive mode without prompting", async () => { readConfigFileSnapshot.mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: true, raw: "{}", parsed: {}, diff --git a/src/commands/doctor.migrates-routing-allowfrom-channels-whatsapp-allowfrom.test.ts b/src/commands/doctor.migrates-routing-allowfrom-channels-whatsapp-allowfrom.test.ts index 09c22616c..728092009 100644 --- a/src/commands/doctor.migrates-routing-allowfrom-channels-whatsapp-allowfrom.test.ts +++ b/src/commands/doctor.migrates-routing-allowfrom-channels-whatsapp-allowfrom.test.ts @@ -34,7 +34,7 @@ beforeEach(() => { durationMs: 0, }); legacyReadConfigFileSnapshot.mockReset().mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: false, raw: null, parsed: {}, @@ -133,7 +133,7 @@ const runCommandWithTimeout = vi.fn().mockResolvedValue({ const ensureAuthProfileStore = vi.fn().mockReturnValue({ version: 1, profiles: {} }); const legacyReadConfigFileSnapshot = vi.fn().mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: false, raw: null, parsed: {}, @@ -180,7 +180,7 @@ vi.mock("../config/config.js", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, - CONFIG_PATH_CLAWDBOT: "/tmp/clawdbot.json", + CONFIG_PATH_MOLTBOT: "/tmp/moltbot.json", createConfigIO, readConfigFileSnapshot, writeConfigFile, @@ -326,7 +326,7 @@ vi.mock("./doctor-state-migrations.js", () => ({ describe("doctor command", () => { it("migrates routing.allowFrom to channels.whatsapp.allowFrom", { timeout: 60_000 }, async () => { readConfigFileSnapshot.mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: true, raw: "{}", parsed: { routing: { allowFrom: ["+15555550123"] } }, @@ -370,7 +370,7 @@ describe("doctor command", () => { it("migrates legacy gateway services", { timeout: 60_000 }, async () => { readConfigFileSnapshot.mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: true, raw: "{}", parsed: {}, @@ -424,7 +424,7 @@ describe("doctor command", () => { }); readConfigFileSnapshot.mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: true, raw: "{}", parsed: {}, diff --git a/src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.test.ts b/src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.test.ts index e9d9af2d6..865a5b0e8 100644 --- a/src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.test.ts +++ b/src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.test.ts @@ -34,7 +34,7 @@ beforeEach(() => { durationMs: 0, }); legacyReadConfigFileSnapshot.mockReset().mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: false, raw: null, parsed: {}, @@ -133,7 +133,7 @@ const runCommandWithTimeout = vi.fn().mockResolvedValue({ const ensureAuthProfileStore = vi.fn().mockReturnValue({ version: 1, profiles: {} }); const legacyReadConfigFileSnapshot = vi.fn().mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: false, raw: null, parsed: {}, @@ -180,7 +180,7 @@ vi.mock("../config/config.js", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, - CONFIG_PATH_CLAWDBOT: "/tmp/clawdbot.json", + CONFIG_PATH_MOLTBOT: "/tmp/moltbot.json", createConfigIO, readConfigFileSnapshot, writeConfigFile, @@ -326,7 +326,7 @@ vi.mock("./doctor-state-migrations.js", () => ({ describe("doctor command", () => { it("runs legacy state migrations in yes mode without prompting", async () => { readConfigFileSnapshot.mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: true, raw: "{}", parsed: {}, @@ -385,7 +385,7 @@ describe("doctor command", () => { it("skips gateway restarts in non-interactive mode", async () => { readConfigFileSnapshot.mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: true, raw: "{}", parsed: {}, @@ -417,7 +417,7 @@ describe("doctor command", () => { it("migrates anthropic oauth config profile id when only email profile exists", async () => { readConfigFileSnapshot.mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: true, raw: "{}", parsed: {}, diff --git a/src/commands/doctor.ts b/src/commands/doctor.ts index aa4f4d7a3..f9c4b64e7 100644 --- a/src/commands/doctor.ts +++ b/src/commands/doctor.ts @@ -11,7 +11,7 @@ import { } from "../agents/model-selection.js"; import { formatCliCommand } from "../cli/command-format.js"; import type { ClawdbotConfig } from "../config/config.js"; -import { CONFIG_PATH_CLAWDBOT, readConfigFileSnapshot, writeConfigFile } from "../config/config.js"; +import { CONFIG_PATH_MOLTBOT, readConfigFileSnapshot, writeConfigFile } from "../config/config.js"; import { logConfigUpdated } from "../config/logging.js"; import { resolveGatewayService } from "../daemon/service.js"; import { resolveGatewayAuth } from "../gateway/auth.js"; @@ -90,7 +90,7 @@ export async function doctorCommand( }); let cfg: ClawdbotConfig = configResult.cfg; - const configPath = configResult.path ?? CONFIG_PATH_CLAWDBOT; + const configPath = configResult.path ?? CONFIG_PATH_MOLTBOT; if (!cfg.gateway?.mode) { const lines = [ "gateway.mode is unset; gateway start will be blocked.", @@ -174,7 +174,7 @@ export async function doctorCommand( } } - await noteStateIntegrity(cfg, prompter, configResult.path ?? CONFIG_PATH_CLAWDBOT); + await noteStateIntegrity(cfg, prompter, configResult.path ?? CONFIG_PATH_MOLTBOT); cfg = await maybeRepairSandboxImages(cfg, runtime, prompter); noteSandboxScopeWarnings(cfg); @@ -272,7 +272,7 @@ export async function doctorCommand( cfg = applyWizardMetadata(cfg, { command: "doctor", mode: resolveMode(cfg) }); await writeConfigFile(cfg); logConfigUpdated(runtime); - const backupPath = `${CONFIG_PATH_CLAWDBOT}.bak`; + const backupPath = `${CONFIG_PATH_MOLTBOT}.bak`; if (fs.existsSync(backupPath)) { runtime.log(`Backup: ${shortenHomePath(backupPath)}`); } diff --git a/src/commands/doctor.warns-per-agent-sandbox-docker-browser-prune.test.ts b/src/commands/doctor.warns-per-agent-sandbox-docker-browser-prune.test.ts index be5f33ee6..8aa7b513e 100644 --- a/src/commands/doctor.warns-per-agent-sandbox-docker-browser-prune.test.ts +++ b/src/commands/doctor.warns-per-agent-sandbox-docker-browser-prune.test.ts @@ -34,7 +34,7 @@ beforeEach(() => { durationMs: 0, }); legacyReadConfigFileSnapshot.mockReset().mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: false, raw: null, parsed: {}, @@ -133,7 +133,7 @@ const runCommandWithTimeout = vi.fn().mockResolvedValue({ const ensureAuthProfileStore = vi.fn().mockReturnValue({ version: 1, profiles: {} }); const legacyReadConfigFileSnapshot = vi.fn().mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: false, raw: null, parsed: {}, @@ -180,7 +180,7 @@ vi.mock("../config/config.js", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, - CONFIG_PATH_CLAWDBOT: "/tmp/clawdbot.json", + CONFIG_PATH_MOLTBOT: "/tmp/moltbot.json", createConfigIO, readConfigFileSnapshot, writeConfigFile, @@ -326,7 +326,7 @@ vi.mock("./doctor-state-migrations.js", () => ({ describe("doctor command", () => { it("warns when per-agent sandbox docker/browser/prune overrides are ignored under shared scope", async () => { readConfigFileSnapshot.mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: true, raw: "{}", parsed: {}, @@ -383,7 +383,7 @@ describe("doctor command", () => { it("warns when extra workspace directories exist", async () => { readConfigFileSnapshot.mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: true, raw: "{}", parsed: {}, diff --git a/src/commands/doctor.warns-state-directory-is-missing.test.ts b/src/commands/doctor.warns-state-directory-is-missing.test.ts index ccbeacaf4..117d74a9b 100644 --- a/src/commands/doctor.warns-state-directory-is-missing.test.ts +++ b/src/commands/doctor.warns-state-directory-is-missing.test.ts @@ -34,7 +34,7 @@ beforeEach(() => { durationMs: 0, }); legacyReadConfigFileSnapshot.mockReset().mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: false, raw: null, parsed: {}, @@ -133,7 +133,7 @@ const runCommandWithTimeout = vi.fn().mockResolvedValue({ const ensureAuthProfileStore = vi.fn().mockReturnValue({ version: 1, profiles: {} }); const legacyReadConfigFileSnapshot = vi.fn().mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: false, raw: null, parsed: {}, @@ -180,7 +180,7 @@ vi.mock("../config/config.js", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, - CONFIG_PATH_CLAWDBOT: "/tmp/clawdbot.json", + CONFIG_PATH_MOLTBOT: "/tmp/moltbot.json", createConfigIO, readConfigFileSnapshot, writeConfigFile, @@ -330,7 +330,7 @@ vi.mock("./doctor-update.js", () => ({ describe("doctor command", () => { it("warns when the state directory is missing", async () => { readConfigFileSnapshot.mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: true, raw: "{}", parsed: {}, @@ -358,7 +358,7 @@ describe("doctor command", () => { it("warns about opencode provider overrides", async () => { readConfigFileSnapshot.mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: true, raw: "{}", parsed: {}, @@ -392,7 +392,7 @@ describe("doctor command", () => { it("skips gateway auth warning when CLAWDBOT_GATEWAY_TOKEN is set", async () => { readConfigFileSnapshot.mockResolvedValue({ - path: "/tmp/clawdbot.json", + path: "/tmp/moltbot.json", exists: true, raw: "{}", parsed: {}, diff --git a/src/commands/models.list.test.ts b/src/commands/models.list.test.ts index e904e3484..741e13f0b 100644 --- a/src/commands/models.list.test.ts +++ b/src/commands/models.list.test.ts @@ -17,8 +17,8 @@ const discoverAuthStorage = vi.fn().mockReturnValue({}); const discoverModels = vi.fn(); vi.mock("../config/config.js", () => ({ - CONFIG_PATH_CLAWDBOT: "/tmp/clawdbot.json", - STATE_DIR_CLAWDBOT: "/tmp/clawdbot-state", + CONFIG_PATH_MOLTBOT: "/tmp/moltbot.json", + STATE_DIR_MOLTBOT: "/tmp/moltbot-state", loadConfig, })); diff --git a/src/commands/models.set.test.ts b/src/commands/models.set.test.ts index d231a5cc8..9ae64204f 100644 --- a/src/commands/models.set.test.ts +++ b/src/commands/models.set.test.ts @@ -5,7 +5,7 @@ const writeConfigFile = vi.fn().mockResolvedValue(undefined); const loadConfig = vi.fn().mockReturnValue({}); vi.mock("../config/config.js", () => ({ - CONFIG_PATH_CLAWDBOT: "/tmp/clawdbot.json", + CONFIG_PATH_MOLTBOT: "/tmp/clawdbot.json", readConfigFileSnapshot, writeConfigFile, loadConfig, diff --git a/src/commands/models/list.status-command.ts b/src/commands/models/list.status-command.ts index 8aa7015c8..7ce8e7f4b 100644 --- a/src/commands/models/list.status-command.ts +++ b/src/commands/models/list.status-command.ts @@ -17,7 +17,7 @@ import { resolveConfiguredModelRef, resolveModelRefFromString, } from "../../agents/model-selection.js"; -import { CONFIG_PATH_CLAWDBOT, loadConfig } from "../../config/config.js"; +import { CONFIG_PATH_MOLTBOT, loadConfig } from "../../config/config.js"; import { getShellEnvAppliedKeys, shouldEnableShellEnvFallback } from "../../infra/shell-env.js"; import { withProgressTotals } from "../../cli/progress.js"; import { @@ -294,7 +294,7 @@ export async function modelsStatusCommand( runtime.log( JSON.stringify( { - configPath: CONFIG_PATH_CLAWDBOT, + configPath: CONFIG_PATH_MOLTBOT, agentDir, defaultModel: defaultLabel, resolvedDefault: resolvedLabel, @@ -341,7 +341,7 @@ export async function modelsStatusCommand( rawModel && rawModel !== resolvedLabel ? `${resolvedLabel} (from ${rawModel})` : resolvedLabel; runtime.log( - `${label("Config")}${colorize(rich, theme.muted, ":")} ${colorize(rich, theme.info, shortenHomePath(CONFIG_PATH_CLAWDBOT))}`, + `${label("Config")}${colorize(rich, theme.muted, ":")} ${colorize(rich, theme.info, shortenHomePath(CONFIG_PATH_MOLTBOT))}`, ); runtime.log( `${label("Agent dir")}${colorize(rich, theme.muted, ":")} ${colorize( diff --git a/src/commands/onboard-helpers.ts b/src/commands/onboard-helpers.ts index dd8288a60..a64d5be14 100644 --- a/src/commands/onboard-helpers.ts +++ b/src/commands/onboard-helpers.ts @@ -7,7 +7,7 @@ import { cancel, isCancel } from "@clack/prompts"; import { DEFAULT_AGENT_WORKSPACE_DIR, ensureAgentWorkspace } from "../agents/workspace.js"; import type { ClawdbotConfig } from "../config/config.js"; -import { CONFIG_PATH_CLAWDBOT } from "../config/config.js"; +import { CONFIG_PATH_MOLTBOT } from "../config/config.js"; import { resolveSessionTranscriptsDirForAgent } from "../config/sessions.js"; import { callGateway } from "../gateway/call.js"; import { normalizeControlUiBasePath } from "../gateway/control-ui-shared.js"; @@ -274,7 +274,7 @@ export async function moveToTrash(pathname: string, runtime: RuntimeEnv): Promis } export async function handleReset(scope: ResetScope, workspaceDir: string, runtime: RuntimeEnv) { - await moveToTrash(CONFIG_PATH_CLAWDBOT, runtime); + await moveToTrash(CONFIG_PATH_MOLTBOT, runtime); if (scope === "config") return; await moveToTrash(path.join(CONFIG_DIR, "credentials"), runtime); await moveToTrash(resolveSessionTranscriptsDirForAgent(), runtime); diff --git a/src/commands/onboard-non-interactive.ai-gateway.test.ts b/src/commands/onboard-non-interactive.ai-gateway.test.ts index fbd9b08dc..4c93c21b6 100644 --- a/src/commands/onboard-non-interactive.ai-gateway.test.ts +++ b/src/commands/onboard-non-interactive.ai-gateway.test.ts @@ -56,8 +56,8 @@ describe("onboard (non-interactive): Vercel AI Gateway", () => { runtime, ); - const { CONFIG_PATH_CLAWDBOT } = await import("../config/config.js"); - const cfg = JSON.parse(await fs.readFile(CONFIG_PATH_CLAWDBOT, "utf8")) as { + const { CONFIG_PATH_MOLTBOT } = await import("../config/config.js"); + const cfg = JSON.parse(await fs.readFile(CONFIG_PATH_MOLTBOT, "utf8")) as { auth?: { profiles?: Record; }; diff --git a/src/commands/onboard-non-interactive.token.test.ts b/src/commands/onboard-non-interactive.token.test.ts index f2455ff24..04c9a9461 100644 --- a/src/commands/onboard-non-interactive.token.test.ts +++ b/src/commands/onboard-non-interactive.token.test.ts @@ -59,8 +59,8 @@ describe("onboard (non-interactive): token auth", () => { runtime, ); - const { CONFIG_PATH_CLAWDBOT } = await import("../config/config.js"); - const cfg = JSON.parse(await fs.readFile(CONFIG_PATH_CLAWDBOT, "utf8")) as { + const { CONFIG_PATH_MOLTBOT } = await import("../config/config.js"); + const cfg = JSON.parse(await fs.readFile(CONFIG_PATH_MOLTBOT, "utf8")) as { auth?: { profiles?: Record; }; diff --git a/src/commands/setup.ts b/src/commands/setup.ts index 0516512ce..eea161a4a 100644 --- a/src/commands/setup.ts +++ b/src/commands/setup.ts @@ -3,7 +3,7 @@ import fs from "node:fs/promises"; import JSON5 from "json5"; import { DEFAULT_AGENT_WORKSPACE_DIR, ensureAgentWorkspace } from "../agents/workspace.js"; -import { type ClawdbotConfig, CONFIG_PATH_CLAWDBOT, writeConfigFile } from "../config/config.js"; +import { type ClawdbotConfig, CONFIG_PATH_MOLTBOT, writeConfigFile } from "../config/config.js"; import { formatConfigPath, logConfigUpdated } from "../config/logging.js"; import { resolveSessionTranscriptsDir } from "../config/sessions.js"; import type { RuntimeEnv } from "../runtime.js"; @@ -15,7 +15,7 @@ async function readConfigFileRaw(): Promise<{ parsed: ClawdbotConfig; }> { try { - const raw = await fs.readFile(CONFIG_PATH_CLAWDBOT, "utf-8"); + const raw = await fs.readFile(CONFIG_PATH_MOLTBOT, "utf-8"); const parsed = JSON5.parse(raw); if (parsed && typeof parsed === "object") { return { exists: true, parsed: parsed as ClawdbotConfig }; diff --git a/src/config/config.nix-integration-u3-u5-u9.test.ts b/src/config/config.nix-integration-u3-u5-u9.test.ts index ac43b29b5..8b50da3d9 100644 --- a/src/config/config.nix-integration-u3-u5-u9.test.ts +++ b/src/config/config.nix-integration-u3-u5-u9.test.ts @@ -35,56 +35,56 @@ describe("Nix integration (U3, U5, U9)", () => { }); describe("U5: CONFIG_PATH and STATE_DIR env var overrides", () => { - it("STATE_DIR_CLAWDBOT defaults to ~/.clawdbot when env not set", async () => { - await withEnvOverride({ CLAWDBOT_STATE_DIR: undefined }, async () => { - const { STATE_DIR_CLAWDBOT } = await import("./config.js"); - expect(STATE_DIR_CLAWDBOT).toMatch(/\.clawdbot$/); + it("STATE_DIR_MOLTBOT defaults to ~/.moltbot when env not set", async () => { + await withEnvOverride({ MOLTBOT_STATE_DIR: undefined }, async () => { + const { STATE_DIR_MOLTBOT } = await import("./config.js"); + expect(STATE_DIR_MOLTBOT).toMatch(/\.moltbot$/); }); }); - it("STATE_DIR_CLAWDBOT respects CLAWDBOT_STATE_DIR override", async () => { - await withEnvOverride({ CLAWDBOT_STATE_DIR: "/custom/state/dir" }, async () => { - const { STATE_DIR_CLAWDBOT } = await import("./config.js"); - expect(STATE_DIR_CLAWDBOT).toBe(path.resolve("/custom/state/dir")); + it("STATE_DIR_MOLTBOT respects MOLTBOT_STATE_DIR override", async () => { + await withEnvOverride({ MOLTBOT_STATE_DIR: "/custom/state/dir" }, async () => { + const { STATE_DIR_MOLTBOT } = await import("./config.js"); + expect(STATE_DIR_MOLTBOT).toBe(path.resolve("/custom/state/dir")); }); }); - it("CONFIG_PATH_CLAWDBOT defaults to ~/.clawdbot/clawdbot.json when env not set", async () => { + it("CONFIG_PATH_MOLTBOT defaults to ~/.moltbot/moltbot.json when env not set", async () => { await withEnvOverride( - { CLAWDBOT_CONFIG_PATH: undefined, CLAWDBOT_STATE_DIR: undefined }, + { MOLTBOT_CONFIG_PATH: undefined, MOLTBOT_STATE_DIR: undefined }, async () => { - const { CONFIG_PATH_CLAWDBOT } = await import("./config.js"); - expect(CONFIG_PATH_CLAWDBOT).toMatch(/\.clawdbot[\\/]clawdbot\.json$/); + const { CONFIG_PATH_MOLTBOT } = await import("./config.js"); + expect(CONFIG_PATH_MOLTBOT).toMatch(/\.moltbot[\\/]clawdbot\.json$/); }, ); }); - it("CONFIG_PATH_CLAWDBOT respects CLAWDBOT_CONFIG_PATH override", async () => { - await withEnvOverride({ CLAWDBOT_CONFIG_PATH: "/nix/store/abc/clawdbot.json" }, async () => { - const { CONFIG_PATH_CLAWDBOT } = await import("./config.js"); - expect(CONFIG_PATH_CLAWDBOT).toBe(path.resolve("/nix/store/abc/clawdbot.json")); + it("CONFIG_PATH_MOLTBOT respects MOLTBOT_CONFIG_PATH override", async () => { + await withEnvOverride({ MOLTBOT_CONFIG_PATH: "/nix/store/abc/moltbot.json" }, async () => { + const { CONFIG_PATH_MOLTBOT } = await import("./config.js"); + expect(CONFIG_PATH_MOLTBOT).toBe(path.resolve("/nix/store/abc/moltbot.json")); }); }); - it("CONFIG_PATH_CLAWDBOT expands ~ in CLAWDBOT_CONFIG_PATH override", async () => { + it("CONFIG_PATH_MOLTBOT expands ~ in MOLTBOT_CONFIG_PATH override", async () => { await withTempHome(async (home) => { - await withEnvOverride({ CLAWDBOT_CONFIG_PATH: "~/.clawdbot/custom.json" }, async () => { - const { CONFIG_PATH_CLAWDBOT } = await import("./config.js"); - expect(CONFIG_PATH_CLAWDBOT).toBe(path.join(home, ".clawdbot", "custom.json")); + await withEnvOverride({ MOLTBOT_CONFIG_PATH: "~/.moltbot/custom.json" }, async () => { + const { CONFIG_PATH_MOLTBOT } = await import("./config.js"); + expect(CONFIG_PATH_MOLTBOT).toBe(path.join(home, ".moltbot", "custom.json")); }); }); }); - it("CONFIG_PATH_CLAWDBOT uses STATE_DIR_CLAWDBOT when only state dir is overridden", async () => { + it("CONFIG_PATH_MOLTBOT uses STATE_DIR_MOLTBOT when only state dir is overridden", async () => { await withEnvOverride( { - CLAWDBOT_CONFIG_PATH: undefined, - CLAWDBOT_STATE_DIR: "/custom/state", + MOLTBOT_CONFIG_PATH: undefined, + MOLTBOT_STATE_DIR: "/custom/state", }, async () => { - const { CONFIG_PATH_CLAWDBOT } = await import("./config.js"); - expect(CONFIG_PATH_CLAWDBOT).toBe( - path.join(path.resolve("/custom/state"), "clawdbot.json"), + const { CONFIG_PATH_MOLTBOT } = await import("./config.js"); + expect(CONFIG_PATH_MOLTBOT).toBe( + path.join(path.resolve("/custom/state"), "moltbot.json"), ); }, ); @@ -94,7 +94,7 @@ describe("Nix integration (U3, U5, U9)", () => { describe("U5b: tilde expansion for config paths", () => { it("expands ~ in common path-ish config fields", async () => { await withTempHome(async (home) => { - const configDir = path.join(home, ".clawdbot"); + const configDir = path.join(home, ".moltbot"); await fs.mkdir(configDir, { recursive: true }); const pluginDir = path.join(home, "plugins", "demo-plugin"); await fs.mkdir(pluginDir, { recursive: true }); @@ -116,7 +116,7 @@ describe("Nix integration (U3, U5, U9)", () => { "utf-8", ); await fs.writeFile( - path.join(configDir, "clawdbot.json"), + path.join(configDir, "moltbot.json"), JSON.stringify( { plugins: { @@ -130,7 +130,7 @@ describe("Nix integration (U3, U5, U9)", () => { { id: "main", workspace: "~/ws-agent", - agentDir: "~/.clawdbot/agents/main", + agentDir: "~/.moltbot/agents/main", sandbox: { workspaceRoot: "~/sandbox-root" }, }, ], @@ -139,7 +139,7 @@ describe("Nix integration (U3, U5, U9)", () => { whatsapp: { accounts: { personal: { - authDir: "~/.clawdbot/credentials/wa-personal", + authDir: "~/.moltbot/credentials/wa-personal", }, }, }, @@ -159,11 +159,11 @@ describe("Nix integration (U3, U5, U9)", () => { expect(cfg.agents?.defaults?.workspace).toBe(path.join(home, "ws-default")); expect(cfg.agents?.list?.[0]?.workspace).toBe(path.join(home, "ws-agent")); expect(cfg.agents?.list?.[0]?.agentDir).toBe( - path.join(home, ".clawdbot", "agents", "main"), + path.join(home, ".moltbot", "agents", "main"), ); expect(cfg.agents?.list?.[0]?.sandbox?.workspaceRoot).toBe(path.join(home, "sandbox-root")); expect(cfg.channels?.whatsapp?.accounts?.personal?.authDir).toBe( - path.join(home, ".clawdbot", "credentials", "wa-personal"), + path.join(home, ".moltbot", "credentials", "wa-personal"), ); }); }); @@ -195,10 +195,10 @@ describe("Nix integration (U3, U5, U9)", () => { describe("U9: telegram.tokenFile schema validation", () => { it("accepts config with only botToken", async () => { await withTempHome(async (home) => { - const configDir = path.join(home, ".clawdbot"); + const configDir = path.join(home, ".moltbot"); await fs.mkdir(configDir, { recursive: true }); await fs.writeFile( - path.join(configDir, "clawdbot.json"), + path.join(configDir, "moltbot.json"), JSON.stringify({ channels: { telegram: { botToken: "123:ABC" } }, }), @@ -215,10 +215,10 @@ describe("Nix integration (U3, U5, U9)", () => { it("accepts config with only tokenFile", async () => { await withTempHome(async (home) => { - const configDir = path.join(home, ".clawdbot"); + const configDir = path.join(home, ".moltbot"); await fs.mkdir(configDir, { recursive: true }); await fs.writeFile( - path.join(configDir, "clawdbot.json"), + path.join(configDir, "moltbot.json"), JSON.stringify({ channels: { telegram: { tokenFile: "/run/agenix/telegram-token" } }, }), @@ -235,10 +235,10 @@ describe("Nix integration (U3, U5, U9)", () => { it("accepts config with both botToken and tokenFile", async () => { await withTempHome(async (home) => { - const configDir = path.join(home, ".clawdbot"); + const configDir = path.join(home, ".moltbot"); await fs.mkdir(configDir, { recursive: true }); await fs.writeFile( - path.join(configDir, "clawdbot.json"), + path.join(configDir, "moltbot.json"), JSON.stringify({ channels: { telegram: { diff --git a/src/config/io.ts b/src/config/io.ts index 9078ef2a2..db0d24d3d 100644 --- a/src/config/io.ts +++ b/src/config/io.ts @@ -53,8 +53,8 @@ const SHELL_ENV_EXPECTED_KEYS = [ "DISCORD_BOT_TOKEN", "SLACK_BOT_TOKEN", "SLACK_APP_TOKEN", - "CLAWDBOT_GATEWAY_TOKEN", - "CLAWDBOT_GATEWAY_PASSWORD", + "MOLTBOT_GATEWAY_TOKEN", + "MOLTBOT_GATEWAY_PASSWORD", ]; const CONFIG_BACKUP_COUNT = 5; @@ -522,7 +522,7 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) { } // NOTE: These wrappers intentionally do *not* cache the resolved config path at -// module scope. `CLAWDBOT_CONFIG_PATH` (and friends) are expected to work even +// module scope. `MOLTBOT_CONFIG_PATH` (and friends) are expected to work even // when set after the module has been imported (tests, one-off scripts, etc.). const DEFAULT_CONFIG_CACHE_MS = 200; let configCache: { @@ -532,7 +532,7 @@ let configCache: { } | null = null; function resolveConfigCacheMs(env: NodeJS.ProcessEnv): number { - const raw = env.CLAWDBOT_CONFIG_CACHE_MS?.trim(); + const raw = env.MOLTBOT_CONFIG_CACHE_MS?.trim(); if (raw === "" || raw === "0") return 0; if (!raw) return DEFAULT_CONFIG_CACHE_MS; const parsed = Number.parseInt(raw, 10); @@ -541,7 +541,7 @@ function resolveConfigCacheMs(env: NodeJS.ProcessEnv): number { } function shouldUseConfigCache(env: NodeJS.ProcessEnv): boolean { - if (env.CLAWDBOT_DISABLE_CONFIG_CACHE?.trim()) return false; + if (env.MOLTBOT_DISABLE_CONFIG_CACHE?.trim()) return false; return resolveConfigCacheMs(env) > 0; } diff --git a/src/config/logging.ts b/src/config/logging.ts index 72c097d7a..d151b0f75 100644 --- a/src/config/logging.ts +++ b/src/config/logging.ts @@ -1,18 +1,18 @@ import type { RuntimeEnv } from "../runtime.js"; import { displayPath } from "../utils.js"; -import { CONFIG_PATH_CLAWDBOT } from "./paths.js"; +import { CONFIG_PATH_MOLTBOT } from "./paths.js"; type LogConfigUpdatedOptions = { path?: string; suffix?: string; }; -export function formatConfigPath(path: string = CONFIG_PATH_CLAWDBOT): string { +export function formatConfigPath(path: string = CONFIG_PATH_MOLTBOT): string { return displayPath(path); } export function logConfigUpdated(runtime: RuntimeEnv, opts: LogConfigUpdatedOptions = {}): void { - const path = formatConfigPath(opts.path ?? CONFIG_PATH_CLAWDBOT); + const path = formatConfigPath(opts.path ?? CONFIG_PATH_MOLTBOT); const suffix = opts.suffix ? ` ${opts.suffix}` : ""; runtime.log(`Updated ${path}${suffix}`); } diff --git a/src/config/paths.ts b/src/config/paths.ts index c3151c1be..bd20de99b 100644 --- a/src/config/paths.ts +++ b/src/config/paths.ts @@ -15,18 +15,30 @@ export function resolveIsNixMode(env: NodeJS.ProcessEnv = process.env): boolean export const isNixMode = resolveIsNixMode(); +const LEGACY_STATE_DIRNAME = ".clawdbot"; +const NEW_STATE_DIRNAME = ".moltbot"; +const CONFIG_FILENAME = "moltbot.json"; + +function legacyStateDir(homedir: () => string = os.homedir): string { + return path.join(homedir(), LEGACY_STATE_DIRNAME); +} + +function newStateDir(homedir: () => string = os.homedir): string { + return path.join(homedir(), NEW_STATE_DIRNAME); +} + /** * State directory for mutable data (sessions, logs, caches). - * Can be overridden via CLAWDBOT_STATE_DIR environment variable. - * Default: ~/.clawdbot + * Can be overridden via MOLTBOT_STATE_DIR (preferred) or CLAWDBOT_STATE_DIR (legacy). + * Default: ~/.clawdbot (legacy default for compatibility) */ export function resolveStateDir( env: NodeJS.ProcessEnv = process.env, homedir: () => string = os.homedir, ): string { - const override = env.CLAWDBOT_STATE_DIR?.trim(); + const override = env.MOLTBOT_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim(); if (override) return resolveUserPath(override); - return path.join(homedir(), ".clawdbot"); + return legacyStateDir(homedir); } function resolveUserPath(input: string): string { @@ -39,34 +51,64 @@ function resolveUserPath(input: string): string { return path.resolve(trimmed); } -export const STATE_DIR_CLAWDBOT = resolveStateDir(); +/** @deprecated Use STATE_DIR. Kept for compatibility during migration. */ +export const STATE_DIR_MOLTBOT = resolveStateDir(); +export const STATE_DIR = resolveStateDir(); /** * Config file path (JSON5). - * Can be overridden via CLAWDBOT_CONFIG_PATH environment variable. - * Default: ~/.clawdbot/clawdbot.json (or $CLAWDBOT_STATE_DIR/clawdbot.json) + * Can be overridden via MOLTBOT_CONFIG_PATH (preferred) or CLAWDBOT_CONFIG_PATH (legacy). + * Default: ~/.clawdbot/moltbot.json (or $*_STATE_DIR/moltbot.json) */ export function resolveConfigPath( env: NodeJS.ProcessEnv = process.env, stateDir: string = resolveStateDir(env, os.homedir), ): string { - const override = env.CLAWDBOT_CONFIG_PATH?.trim(); + const override = env.MOLTBOT_CONFIG_PATH?.trim() || env.CLAWDBOT_CONFIG_PATH?.trim(); if (override) return resolveUserPath(override); - return path.join(stateDir, "clawdbot.json"); + return path.join(stateDir, CONFIG_FILENAME); } -export const CONFIG_PATH_CLAWDBOT = resolveConfigPath(); +/** @deprecated Use CONFIG_PATH. Kept for compatibility during migration. */ +export const CONFIG_PATH_MOLTBOT = resolveConfigPath(); +export const CONFIG_PATH = resolveConfigPath(); + +/** + * Resolve default config path candidates across new + legacy locations. + * Order: explicit config path → state-dir-derived paths → new default → legacy default. + */ +export function resolveDefaultConfigCandidates( + env: NodeJS.ProcessEnv = process.env, + homedir: () => string = os.homedir, +): string[] { + const explicit = env.MOLTBOT_CONFIG_PATH?.trim() || env.CLAWDBOT_CONFIG_PATH?.trim(); + if (explicit) return [resolveUserPath(explicit)]; + + const candidates: string[] = []; + const moltbotStateDir = env.MOLTBOT_STATE_DIR?.trim(); + if (moltbotStateDir) { + candidates.push(path.join(resolveUserPath(moltbotStateDir), CONFIG_FILENAME)); + } + const legacyStateDirOverride = env.CLAWDBOT_STATE_DIR?.trim(); + if (legacyStateDirOverride) { + candidates.push(path.join(resolveUserPath(legacyStateDirOverride), CONFIG_FILENAME)); + } + + candidates.push(path.join(newStateDir(homedir), CONFIG_FILENAME)); + candidates.push(path.join(legacyStateDir(homedir), CONFIG_FILENAME)); + return candidates; +} export const DEFAULT_GATEWAY_PORT = 18789; /** * Gateway lock directory (ephemeral). - * Default: os.tmpdir()/clawdbot- (uid suffix when available). + * Default: os.tmpdir()/moltbot- (uid suffix when available). */ export function resolveGatewayLockDir(tmpdir: () => string = os.tmpdir): string { const base = tmpdir(); const uid = typeof process.getuid === "function" ? process.getuid() : undefined; - const suffix = uid != null ? `clawdbot-${uid}` : "clawdbot"; + const suffix = uid != null ? `moltbot-${uid}` : "moltbot"; return path.join(base, suffix); } @@ -77,7 +119,7 @@ const OAUTH_FILENAME = "oauth.json"; * * Precedence: * - `CLAWDBOT_OAUTH_DIR` (explicit override) - * - `CLAWDBOT_STATE_DIR/credentials` (canonical server/default) + * - `$*_STATE_DIR/credentials` (canonical server/default) * - `~/.clawdbot/credentials` (legacy default) */ export function resolveOAuthDir( diff --git a/src/gateway/hooks-mapping.ts b/src/gateway/hooks-mapping.ts index 11fd35ee0..79535cbfa 100644 --- a/src/gateway/hooks-mapping.ts +++ b/src/gateway/hooks-mapping.ts @@ -2,7 +2,7 @@ import path from "node:path"; import { pathToFileURL } from "node:url"; import { - CONFIG_PATH_CLAWDBOT, + CONFIG_PATH_MOLTBOT, type HookMappingConfig, type HooksConfig, } from "../config/config.js"; @@ -125,7 +125,7 @@ export function resolveHookMappings(hooks?: HooksConfig): HookMappingResolved[] } if (mappings.length === 0) return []; - const configDir = path.dirname(CONFIG_PATH_CLAWDBOT); + const configDir = path.dirname(CONFIG_PATH_MOLTBOT); const transformsDir = hooks?.transformsDir ? resolvePath(configDir, hooks.transformsDir) : configDir; diff --git a/src/gateway/server-methods/config.ts b/src/gateway/server-methods/config.ts index d248228ef..030b66e8b 100644 --- a/src/gateway/server-methods/config.ts +++ b/src/gateway/server-methods/config.ts @@ -1,6 +1,6 @@ import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../agents/agent-scope.js"; import { - CONFIG_PATH_CLAWDBOT, + CONFIG_PATH_MOLTBOT, loadConfig, parseConfigJson5, readConfigFileSnapshot, @@ -186,7 +186,7 @@ export const configHandlers: GatewayRequestHandlers = { true, { ok: true, - path: CONFIG_PATH_CLAWDBOT, + path: CONFIG_PATH_MOLTBOT, config: validated.config, }, undefined, @@ -284,7 +284,7 @@ export const configHandlers: GatewayRequestHandlers = { doctorHint: formatDoctorNonInteractiveHint(), stats: { mode: "config.patch", - root: CONFIG_PATH_CLAWDBOT, + root: CONFIG_PATH_MOLTBOT, }, }; let sentinelPath: string | null = null; @@ -301,7 +301,7 @@ export const configHandlers: GatewayRequestHandlers = { true, { ok: true, - path: CONFIG_PATH_CLAWDBOT, + path: CONFIG_PATH_MOLTBOT, config: validated.config, restart, sentinel: { @@ -381,7 +381,7 @@ export const configHandlers: GatewayRequestHandlers = { doctorHint: formatDoctorNonInteractiveHint(), stats: { mode: "config.apply", - root: CONFIG_PATH_CLAWDBOT, + root: CONFIG_PATH_MOLTBOT, }, }; let sentinelPath: string | null = null; @@ -398,7 +398,7 @@ export const configHandlers: GatewayRequestHandlers = { true, { ok: true, - path: CONFIG_PATH_CLAWDBOT, + path: CONFIG_PATH_MOLTBOT, config: validated.config, restart, sentinel: { diff --git a/src/gateway/server.auth.e2e.test.ts b/src/gateway/server.auth.e2e.test.ts index 2eb3dcef9..de55a31e0 100644 --- a/src/gateway/server.auth.e2e.test.ts +++ b/src/gateway/server.auth.e2e.test.ts @@ -66,7 +66,7 @@ describe("gateway server auth/connect", () => { }); test("connect (req) handshake returns hello-ok payload", async () => { - const { CONFIG_PATH_CLAWDBOT, STATE_DIR_CLAWDBOT } = await import("../config/config.js"); + const { CONFIG_PATH_MOLTBOT, STATE_DIR_MOLTBOT } = await import("../config/config.js"); const ws = await openWs(port); const res = await connectReq(ws); @@ -78,8 +78,8 @@ describe("gateway server auth/connect", () => { } | undefined; expect(payload?.type).toBe("hello-ok"); - expect(payload?.snapshot?.configPath).toBe(CONFIG_PATH_CLAWDBOT); - expect(payload?.snapshot?.stateDir).toBe(STATE_DIR_CLAWDBOT); + expect(payload?.snapshot?.configPath).toBe(CONFIG_PATH_MOLTBOT); + expect(payload?.snapshot?.stateDir).toBe(STATE_DIR_MOLTBOT); ws.close(); }); diff --git a/src/gateway/server.impl.ts b/src/gateway/server.impl.ts index 7435ed1a7..3b352af98 100644 --- a/src/gateway/server.impl.ts +++ b/src/gateway/server.impl.ts @@ -6,7 +6,7 @@ import { type ChannelId, listChannelPlugins } from "../channels/plugins/index.js import { createDefaultDeps } from "../cli/deps.js"; import { formatCliCommand } from "../cli/command-format.js"; import { - CONFIG_PATH_CLAWDBOT, + CONFIG_PATH_MOLTBOT, isNixMode, loadConfig, migrateLegacyConfig, @@ -541,7 +541,7 @@ export async function startGatewayServer( warn: (msg) => logReload.warn(msg), error: (msg) => logReload.error(msg), }, - watchPath: CONFIG_PATH_CLAWDBOT, + watchPath: CONFIG_PATH_MOLTBOT, }); const close = createGatewayCloseHandler({ diff --git a/src/gateway/server/health-state.ts b/src/gateway/server/health-state.ts index 62ff24616..d130f31e0 100644 --- a/src/gateway/server/health-state.ts +++ b/src/gateway/server/health-state.ts @@ -1,6 +1,6 @@ import { resolveDefaultAgentId } from "../../agents/agent-scope.js"; import { getHealthSnapshot, type HealthSummary } from "../../commands/health.js"; -import { CONFIG_PATH_CLAWDBOT, STATE_DIR_CLAWDBOT, loadConfig } from "../../config/config.js"; +import { CONFIG_PATH_MOLTBOT, STATE_DIR_MOLTBOT, loadConfig } from "../../config/config.js"; import { resolveMainSessionKey } from "../../config/sessions.js"; import { normalizeMainKey } from "../../routing/session-key.js"; import { listSystemPresence } from "../../infra/system-presence.js"; @@ -28,8 +28,8 @@ export function buildGatewaySnapshot(): Snapshot { stateVersion: { presence: presenceVersion, health: healthVersion }, uptimeMs, // Surface resolved paths so UIs can display the true config location. - configPath: CONFIG_PATH_CLAWDBOT, - stateDir: STATE_DIR_CLAWDBOT, + configPath: CONFIG_PATH_MOLTBOT, + stateDir: STATE_DIR_MOLTBOT, sessionDefaults: { defaultAgentId, mainKey, diff --git a/src/gateway/test-helpers.mocks.ts b/src/gateway/test-helpers.mocks.ts index c740bba66..190ba22d9 100644 --- a/src/gateway/test-helpers.mocks.ts +++ b/src/gateway/test-helpers.mocks.ts @@ -350,10 +350,10 @@ vi.mock("../config/config.js", async () => { return { ...actual, - get CONFIG_PATH_CLAWDBOT() { + get CONFIG_PATH_MOLTBOT() { return resolveConfigPath(); }, - get STATE_DIR_CLAWDBOT() { + get STATE_DIR_MOLTBOT() { return path.dirname(resolveConfigPath()); }, get isNixMode() { diff --git a/src/hooks/gmail-ops.ts b/src/hooks/gmail-ops.ts index 8712caac8..a39ba4028 100644 --- a/src/hooks/gmail-ops.ts +++ b/src/hooks/gmail-ops.ts @@ -2,7 +2,7 @@ import { spawn } from "node:child_process"; import { type ClawdbotConfig, - CONFIG_PATH_CLAWDBOT, + CONFIG_PATH_MOLTBOT, loadConfig, readConfigFileSnapshot, resolveGatewayPort, @@ -99,7 +99,7 @@ export async function runGmailSetup(opts: GmailSetupOptions) { const configSnapshot = await readConfigFileSnapshot(); if (!configSnapshot.valid) { - throw new Error(`Config invalid: ${CONFIG_PATH_CLAWDBOT}`); + throw new Error(`Config invalid: ${CONFIG_PATH_MOLTBOT}`); } const baseConfig = configSnapshot.config; @@ -277,7 +277,7 @@ export async function runGmailSetup(opts: GmailSetupOptions) { defaultRuntime.log(`- subscription: ${subscription}`); defaultRuntime.log(`- push endpoint: ${pushEndpoint}`); defaultRuntime.log(`- hook url: ${hookUrl}`); - defaultRuntime.log(`- config: ${displayPath(CONFIG_PATH_CLAWDBOT)}`); + defaultRuntime.log(`- config: ${displayPath(CONFIG_PATH_MOLTBOT)}`); defaultRuntime.log(`Next: ${formatCliCommand("clawdbot webhooks gmail run")}`); } diff --git a/src/plugins/services.ts b/src/plugins/services.ts index 604224477..714fec1ed 100644 --- a/src/plugins/services.ts +++ b/src/plugins/services.ts @@ -1,5 +1,5 @@ import type { ClawdbotConfig } from "../config/config.js"; -import { STATE_DIR_CLAWDBOT } from "../config/paths.js"; +import { STATE_DIR_MOLTBOT } from "../config/paths.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import type { PluginRegistry } from "./registry.js"; @@ -25,7 +25,7 @@ export async function startPluginServices(params: { await service.start({ config: params.config, workspaceDir: params.workspaceDir, - stateDir: STATE_DIR_CLAWDBOT, + stateDir: STATE_DIR_MOLTBOT, logger: { info: (msg) => log.info(msg), warn: (msg) => log.warn(msg), @@ -40,7 +40,7 @@ export async function startPluginServices(params: { service.stop?.({ config: params.config, workspaceDir: params.workspaceDir, - stateDir: STATE_DIR_CLAWDBOT, + stateDir: STATE_DIR_MOLTBOT, logger: { info: (msg) => log.info(msg), warn: (msg) => log.warn(msg),