mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 04:51:25 +00:00
refactor: rename clawdbot to moltbot with legacy compat
This commit is contained in:
@@ -9,7 +9,7 @@ import { extractArchive, resolveArchiveKind, resolvePackedRootDir } from "./arch
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
async function makeTempDir() {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-archive-"));
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-archive-"));
|
||||
tempDirs.push(dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ describe("bonjour-discovery", () => {
|
||||
if (domain === "local.") {
|
||||
return {
|
||||
stdout: [
|
||||
"Add 2 3 local. _clawdbot-gw._tcp. Peter\\226\\128\\153s Mac Studio Gateway",
|
||||
"Add 2 3 local. _clawdbot-gw._tcp. Laptop Gateway",
|
||||
"Add 2 3 local. _moltbot-gw._tcp. Peter\\226\\128\\153s Mac Studio Gateway",
|
||||
"Add 2 3 local. _moltbot-gw._tcp. Laptop Gateway",
|
||||
"",
|
||||
].join("\n"),
|
||||
stderr: "",
|
||||
@@ -30,7 +30,7 @@ describe("bonjour-discovery", () => {
|
||||
if (domain === WIDE_AREA_DISCOVERY_DOMAIN) {
|
||||
return {
|
||||
stdout: [
|
||||
`Add 2 3 ${WIDE_AREA_DISCOVERY_DOMAIN} _clawdbot-gw._tcp. Tailnet Gateway`,
|
||||
`Add 2 3 ${WIDE_AREA_DISCOVERY_DOMAIN} _moltbot-gw._tcp. Tailnet Gateway`,
|
||||
"",
|
||||
].join("\n"),
|
||||
stderr: "",
|
||||
@@ -65,7 +65,7 @@ describe("bonjour-discovery", () => {
|
||||
|
||||
return {
|
||||
stdout: [
|
||||
`${instance}._clawdbot-gw._tcp. can be reached at ${host}:18789`,
|
||||
`${instance}._moltbot-gw._tcp. can be reached at ${host}:18789`,
|
||||
txtParts.join(" "),
|
||||
"",
|
||||
].join("\n"),
|
||||
@@ -112,7 +112,7 @@ describe("bonjour-discovery", () => {
|
||||
const domain = argv[3] ?? "";
|
||||
if (argv[0] === "dns-sd" && argv[1] === "-B" && domain === "local.") {
|
||||
return {
|
||||
stdout: ["Add 2 3 local. _clawdbot-gw._tcp. Studio Gateway", ""].join("\n"),
|
||||
stdout: ["Add 2 3 local. _moltbot-gw._tcp. Studio Gateway", ""].join("\n"),
|
||||
stderr: "",
|
||||
code: 0,
|
||||
signal: null,
|
||||
@@ -123,7 +123,7 @@ describe("bonjour-discovery", () => {
|
||||
if (argv[0] === "dns-sd" && argv[1] === "-L") {
|
||||
return {
|
||||
stdout: [
|
||||
"Studio Gateway._clawdbot-gw._tcp. can be reached at studio.local:18789",
|
||||
"Studio Gateway._moltbot-gw._tcp. can be reached at studio.local:18789",
|
||||
"txtvers=1 displayName=Peter\\226\\128\\153s\\032Mac\\032Studio lanHost=studio.local gatewayPort=18789 sshPort=22",
|
||||
"",
|
||||
].join("\n"),
|
||||
@@ -164,6 +164,9 @@ describe("bonjour-discovery", () => {
|
||||
|
||||
it("falls back to tailnet DNS probing for wide-area when split DNS is not configured", async () => {
|
||||
const calls: Array<{ argv: string[]; timeoutMs: number }> = [];
|
||||
const zone = WIDE_AREA_DISCOVERY_DOMAIN.replace(/\.$/, "");
|
||||
const serviceBase = `_moltbot-gw._tcp.${zone}`;
|
||||
const studioService = `studio-gateway.${serviceBase}`;
|
||||
|
||||
const run = vi.fn(async (argv: string[], options: { timeoutMs: number }) => {
|
||||
calls.push({ argv, timeoutMs: options.timeoutMs });
|
||||
@@ -200,13 +203,9 @@ describe("bonjour-discovery", () => {
|
||||
const qname = argv[argv.length - 2] ?? "";
|
||||
const qtype = argv[argv.length - 1] ?? "";
|
||||
|
||||
if (
|
||||
server === "100.123.224.76" &&
|
||||
qtype === "PTR" &&
|
||||
qname === "_clawdbot-gw._tcp.clawdbot.internal"
|
||||
) {
|
||||
if (server === "100.123.224.76" && qtype === "PTR" && qname === serviceBase) {
|
||||
return {
|
||||
stdout: `studio-gateway._clawdbot-gw._tcp.clawdbot.internal.\n`,
|
||||
stdout: `${studioService}.\n`,
|
||||
stderr: "",
|
||||
code: 0,
|
||||
signal: null,
|
||||
@@ -214,13 +213,9 @@ describe("bonjour-discovery", () => {
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
server === "100.123.224.76" &&
|
||||
qtype === "SRV" &&
|
||||
qname === "studio-gateway._clawdbot-gw._tcp.clawdbot.internal"
|
||||
) {
|
||||
if (server === "100.123.224.76" && qtype === "SRV" && qname === studioService) {
|
||||
return {
|
||||
stdout: `0 0 18789 studio.clawdbot.internal.\n`,
|
||||
stdout: `0 0 18789 studio.${zone}.\n`,
|
||||
stderr: "",
|
||||
code: 0,
|
||||
signal: null,
|
||||
@@ -228,11 +223,7 @@ describe("bonjour-discovery", () => {
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
server === "100.123.224.76" &&
|
||||
qtype === "TXT" &&
|
||||
qname === "studio-gateway._clawdbot-gw._tcp.clawdbot.internal"
|
||||
) {
|
||||
if (server === "100.123.224.76" && qtype === "TXT" && qname === studioService) {
|
||||
return {
|
||||
stdout: [
|
||||
`"displayName=Studio"`,
|
||||
@@ -240,7 +231,7 @@ describe("bonjour-discovery", () => {
|
||||
`"transport=gateway"`,
|
||||
`"sshPort=22"`,
|
||||
`"tailnetDns=peters-mac-studio-1.sheep-coho.ts.net"`,
|
||||
`"cliPath=/opt/homebrew/bin/clawdbot"`,
|
||||
`"cliPath=/opt/homebrew/bin/moltbot"`,
|
||||
"",
|
||||
].join(" "),
|
||||
stderr: "",
|
||||
@@ -266,12 +257,12 @@ describe("bonjour-discovery", () => {
|
||||
domain: WIDE_AREA_DISCOVERY_DOMAIN,
|
||||
instanceName: "studio-gateway",
|
||||
displayName: "Studio",
|
||||
host: "studio.clawdbot.internal",
|
||||
host: `studio.${zone}`,
|
||||
port: 18789,
|
||||
tailnetDns: "peters-mac-studio-1.sheep-coho.ts.net",
|
||||
gatewayPort: 18789,
|
||||
sshPort: 22,
|
||||
cliPath: "/opt/homebrew/bin/clawdbot",
|
||||
cliPath: "/opt/homebrew/bin/moltbot",
|
||||
}),
|
||||
]);
|
||||
|
||||
@@ -295,12 +286,12 @@ describe("bonjour-discovery", () => {
|
||||
await discoverGatewayBeacons({
|
||||
platform: "darwin",
|
||||
timeoutMs: 1,
|
||||
domains: ["local", "clawdbot.internal"],
|
||||
domains: ["local", "moltbot.internal"],
|
||||
run: run as unknown as typeof runCommandWithTimeout,
|
||||
});
|
||||
|
||||
expect(calls.filter((c) => c[1] === "-B").map((c) => c[3])).toEqual(
|
||||
expect.arrayContaining(["local.", "clawdbot.internal."]),
|
||||
expect.arrayContaining(["local.", "moltbot.internal."]),
|
||||
);
|
||||
|
||||
calls.length = 0;
|
||||
|
||||
@@ -166,9 +166,9 @@ function parseDnsSdBrowse(stdout: string): string[] {
|
||||
const instances = new Set<string>();
|
||||
for (const raw of stdout.split("\n")) {
|
||||
const line = raw.trim();
|
||||
if (!line || !line.includes("_clawdbot-gw._tcp")) continue;
|
||||
if (!line || !line.includes("_moltbot-gw._tcp")) continue;
|
||||
if (!line.includes("Add")) continue;
|
||||
const match = line.match(/_clawdbot-gw\._tcp\.?\s+(.+)$/);
|
||||
const match = line.match(/_moltbot-gw\._tcp\.?\s+(.+)$/);
|
||||
if (match?.[1]) {
|
||||
instances.add(decodeDnsSdEscapes(match[1].trim()));
|
||||
}
|
||||
@@ -225,13 +225,13 @@ async function discoverViaDnsSd(
|
||||
timeoutMs: number,
|
||||
run: typeof runCommandWithTimeout,
|
||||
): Promise<GatewayBonjourBeacon[]> {
|
||||
const browse = await run(["dns-sd", "-B", "_clawdbot-gw._tcp", domain], {
|
||||
const browse = await run(["dns-sd", "-B", "_moltbot-gw._tcp", domain], {
|
||||
timeoutMs,
|
||||
});
|
||||
const instances = parseDnsSdBrowse(browse.stdout);
|
||||
const results: GatewayBonjourBeacon[] = [];
|
||||
for (const instance of instances) {
|
||||
const resolved = await run(["dns-sd", "-L", instance, "_clawdbot-gw._tcp", domain], {
|
||||
const resolved = await run(["dns-sd", "-L", instance, "_moltbot-gw._tcp", domain], {
|
||||
timeoutMs,
|
||||
});
|
||||
const parsed = parseDnsSdResolve(resolved.stdout, instance);
|
||||
@@ -268,7 +268,7 @@ async function discoverWideAreaViaTailnetDns(
|
||||
// Keep scans bounded: this is a fallback and should not block long.
|
||||
ips = ips.slice(0, 40);
|
||||
|
||||
const probeName = `_clawdbot-gw._tcp.${domain.replace(/\.$/, "")}`;
|
||||
const probeName = `_moltbot-gw._tcp.${domain.replace(/\.$/, "")}`;
|
||||
|
||||
const concurrency = 6;
|
||||
let nextIndex = 0;
|
||||
@@ -312,7 +312,7 @@ async function discoverWideAreaViaTailnetDns(
|
||||
if (budget <= 0) break;
|
||||
const ptrName = ptr.trim().replace(/\.$/, "");
|
||||
if (!ptrName) continue;
|
||||
const instanceName = ptrName.replace(/\.?_clawdbot-gw\._tcp\..*$/, "");
|
||||
const instanceName = ptrName.replace(/\.?_moltbot-gw\._tcp\..*$/, "");
|
||||
|
||||
const srv = await run(["dig", "+short", "+time=1", "+tries=1", nameserverArg, ptrName, "SRV"], {
|
||||
timeoutMs: Math.max(1, Math.min(350, budget)),
|
||||
@@ -371,9 +371,9 @@ function parseAvahiBrowse(stdout: string): GatewayBonjourBeacon[] {
|
||||
for (const raw of stdout.split("\n")) {
|
||||
const line = raw.trimEnd();
|
||||
if (!line) continue;
|
||||
if (line.startsWith("=") && line.includes("_clawdbot-gw._tcp")) {
|
||||
if (line.startsWith("=") && line.includes("_moltbot-gw._tcp")) {
|
||||
if (current) results.push(current);
|
||||
const marker = " _clawdbot-gw._tcp";
|
||||
const marker = " _moltbot-gw._tcp";
|
||||
const idx = line.indexOf(marker);
|
||||
const left = idx >= 0 ? line.slice(0, idx).trim() : line;
|
||||
const parts = left.split(/\s+/);
|
||||
@@ -429,7 +429,7 @@ async function discoverViaAvahi(
|
||||
timeoutMs: number,
|
||||
run: typeof runCommandWithTimeout,
|
||||
): Promise<GatewayBonjourBeacon[]> {
|
||||
const args = ["avahi-browse", "-rt", "_clawdbot-gw._tcp"];
|
||||
const args = ["avahi-browse", "-rt", "_moltbot-gw._tcp"];
|
||||
if (domain && domain !== "local.") {
|
||||
// avahi-browse wants a plain domain (no trailing dot)
|
||||
args.push("-d", domain.replace(/\.$/, ""));
|
||||
|
||||
@@ -111,12 +111,12 @@ describe("gateway bonjour advertiser", () => {
|
||||
gatewayPort: 18789,
|
||||
sshPort: 2222,
|
||||
tailnetDns: "host.tailnet.ts.net",
|
||||
cliPath: "/opt/homebrew/bin/clawdbot",
|
||||
cliPath: "/opt/homebrew/bin/moltbot",
|
||||
});
|
||||
|
||||
expect(createService).toHaveBeenCalledTimes(1);
|
||||
const [gatewayCall] = createService.mock.calls as Array<[Record<string, unknown>]>;
|
||||
expect(gatewayCall?.[0]?.type).toBe("clawdbot-gw");
|
||||
expect(gatewayCall?.[0]?.type).toBe("moltbot-gw");
|
||||
const gatewayType = asString(gatewayCall?.[0]?.type, "");
|
||||
expect(gatewayType.length).toBeLessThanOrEqual(15);
|
||||
expect(gatewayCall?.[0]?.port).toBe(18789);
|
||||
@@ -126,7 +126,7 @@ describe("gateway bonjour advertiser", () => {
|
||||
expect((gatewayCall?.[0]?.txt as Record<string, string>)?.gatewayPort).toBe("18789");
|
||||
expect((gatewayCall?.[0]?.txt as Record<string, string>)?.sshPort).toBe("2222");
|
||||
expect((gatewayCall?.[0]?.txt as Record<string, string>)?.cliPath).toBe(
|
||||
"/opt/homebrew/bin/clawdbot",
|
||||
"/opt/homebrew/bin/moltbot",
|
||||
);
|
||||
expect((gatewayCall?.[0]?.txt as Record<string, string>)?.transport).toBe("gateway");
|
||||
|
||||
@@ -163,7 +163,7 @@ describe("gateway bonjour advertiser", () => {
|
||||
const started = await startGatewayBonjourAdvertiser({
|
||||
gatewayPort: 18789,
|
||||
sshPort: 2222,
|
||||
cliPath: "/opt/homebrew/bin/clawdbot",
|
||||
cliPath: "/opt/homebrew/bin/moltbot",
|
||||
minimal: true,
|
||||
});
|
||||
|
||||
@@ -364,7 +364,7 @@ describe("gateway bonjour advertiser", () => {
|
||||
});
|
||||
|
||||
const [gatewayCall] = createService.mock.calls as Array<[ServiceCall]>;
|
||||
expect(gatewayCall?.[0]?.name).toBe("Mac (Clawdbot)");
|
||||
expect(gatewayCall?.[0]?.name).toBe("Mac (Moltbot)");
|
||||
expect(gatewayCall?.[0]?.domain).toBe("local");
|
||||
expect(gatewayCall?.[0]?.hostname).toBe("Mac");
|
||||
expect((gatewayCall?.[0]?.txt as Record<string, string>)?.lanHost).toBe("Mac.local");
|
||||
|
||||
@@ -36,12 +36,12 @@ function isDisabledByEnv() {
|
||||
|
||||
function safeServiceName(name: string) {
|
||||
const trimmed = name.trim();
|
||||
return trimmed.length > 0 ? trimmed : "Clawdbot";
|
||||
return trimmed.length > 0 ? trimmed : "Moltbot";
|
||||
}
|
||||
|
||||
function prettifyInstanceName(name: string) {
|
||||
const normalized = name.trim().replace(/\s+/g, " ");
|
||||
return normalized.replace(/\s+\(Clawdbot\)\s*$/i, "").trim() || normalized;
|
||||
return normalized.replace(/\s+\(Moltbot\)\s*$/i, "").trim() || normalized;
|
||||
}
|
||||
|
||||
type BonjourService = {
|
||||
@@ -95,11 +95,11 @@ export async function startGatewayBonjourAdvertiser(
|
||||
.hostname()
|
||||
.replace(/\.local$/i, "")
|
||||
.split(".")[0]
|
||||
.trim() || "clawdbot";
|
||||
.trim() || "moltbot";
|
||||
const instanceName =
|
||||
typeof opts.instanceName === "string" && opts.instanceName.trim()
|
||||
? opts.instanceName.trim()
|
||||
: `${hostname} (Clawdbot)`;
|
||||
: `${hostname} (Moltbot)`;
|
||||
const displayName = prettifyInstanceName(instanceName);
|
||||
|
||||
const txtBase: Record<string, string> = {
|
||||
@@ -140,7 +140,7 @@ export async function startGatewayBonjourAdvertiser(
|
||||
|
||||
const gateway = responder.createService({
|
||||
name: safeServiceName(instanceName),
|
||||
type: "clawdbot-gw",
|
||||
type: "moltbot-gw",
|
||||
protocol: Protocol.TCP,
|
||||
port: opts.gatewayPort,
|
||||
domain: "local",
|
||||
|
||||
@@ -8,7 +8,7 @@ import { resolveBrewExecutable, resolveBrewPathDirs } from "./brew.js";
|
||||
|
||||
describe("brew helpers", () => {
|
||||
it("resolves brew from ~/.linuxbrew/bin when executable exists", async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-brew-"));
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-brew-"));
|
||||
try {
|
||||
const homebrewBin = path.join(tmp, ".linuxbrew", "bin");
|
||||
await fs.mkdir(homebrewBin, { recursive: true });
|
||||
@@ -24,7 +24,7 @@ describe("brew helpers", () => {
|
||||
});
|
||||
|
||||
it("prefers HOMEBREW_PREFIX/bin/brew when present", async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-brew-"));
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-brew-"));
|
||||
try {
|
||||
const prefix = path.join(tmp, "prefix");
|
||||
const prefixBin = path.join(prefix, "bin");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { listChannelPlugins } from "../channels/plugins/index.js";
|
||||
import type { ChannelAccountSnapshot, ChannelPlugin } from "../channels/plugins/types.js";
|
||||
import { type ClawdbotConfig, loadConfig } from "../config/config.js";
|
||||
import { type MoltbotConfig, loadConfig } from "../config/config.js";
|
||||
import { DEFAULT_ACCOUNT_ID } from "../routing/session-key.js";
|
||||
import { theme } from "../terminal/theme.js";
|
||||
|
||||
@@ -34,7 +34,7 @@ const accountLine = (label: string, details: string[]) =>
|
||||
const resolveAccountEnabled = (
|
||||
plugin: ChannelPlugin,
|
||||
account: unknown,
|
||||
cfg: ClawdbotConfig,
|
||||
cfg: MoltbotConfig,
|
||||
): boolean => {
|
||||
if (plugin.config.isEnabled) {
|
||||
return plugin.config.isEnabled(account, cfg);
|
||||
@@ -47,7 +47,7 @@ const resolveAccountEnabled = (
|
||||
const resolveAccountConfigured = async (
|
||||
plugin: ChannelPlugin,
|
||||
account: unknown,
|
||||
cfg: ClawdbotConfig,
|
||||
cfg: MoltbotConfig,
|
||||
): Promise<boolean> => {
|
||||
if (plugin.config.isConfigured) {
|
||||
return await plugin.config.isConfigured(account, cfg);
|
||||
@@ -58,7 +58,7 @@ const resolveAccountConfigured = async (
|
||||
const buildAccountSnapshot = (params: {
|
||||
plugin: ChannelPlugin;
|
||||
account: unknown;
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
accountId: string;
|
||||
enabled: boolean;
|
||||
configured: boolean;
|
||||
@@ -76,7 +76,7 @@ const buildAccountSnapshot = (params: {
|
||||
|
||||
const formatAllowFrom = (params: {
|
||||
plugin: ChannelPlugin;
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
accountId?: string | null;
|
||||
allowFrom: Array<string | number>;
|
||||
}) => {
|
||||
@@ -93,7 +93,7 @@ const formatAllowFrom = (params: {
|
||||
const buildAccountDetails = (params: {
|
||||
entry: ChannelAccountEntry;
|
||||
plugin: ChannelPlugin;
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
includeAllowFrom: boolean;
|
||||
}): string[] => {
|
||||
const details: string[] = [];
|
||||
@@ -129,7 +129,7 @@ const buildAccountDetails = (params: {
|
||||
};
|
||||
|
||||
export async function buildChannelSummary(
|
||||
cfg?: ClawdbotConfig,
|
||||
cfg?: MoltbotConfig,
|
||||
options?: ChannelSummaryOptions,
|
||||
): Promise<string[]> {
|
||||
const effective = cfg ?? loadConfig();
|
||||
|
||||
@@ -8,7 +8,7 @@ import { resolveControlUiDistIndexPath, resolveControlUiRepoRoot } from "./contr
|
||||
|
||||
describe("control UI assets helpers", () => {
|
||||
it("resolves repo root from src argv1", async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-ui-"));
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-ui-"));
|
||||
try {
|
||||
await fs.mkdir(path.join(tmp, "ui"), { recursive: true });
|
||||
await fs.writeFile(path.join(tmp, "ui", "vite.config.ts"), "export {};\n");
|
||||
@@ -23,7 +23,7 @@ describe("control UI assets helpers", () => {
|
||||
});
|
||||
|
||||
it("resolves repo root from dist argv1", async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-ui-"));
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-ui-"));
|
||||
try {
|
||||
await fs.mkdir(path.join(tmp, "ui"), { recursive: true });
|
||||
await fs.writeFile(path.join(tmp, "ui", "vite.config.ts"), "export {};\n");
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
|
||||
describe("device pairing tokens", () => {
|
||||
test("preserves existing token scopes when rotating without scopes", async () => {
|
||||
const baseDir = await mkdtemp(join(tmpdir(), "clawdbot-device-pairing-"));
|
||||
const baseDir = await mkdtemp(join(tmpdir(), "moltbot-device-pairing-"));
|
||||
const request = await requestDevicePairing(
|
||||
{
|
||||
deviceId: "device-1",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
|
||||
export type DiagnosticSessionState = "idle" | "processing" | "waiting";
|
||||
|
||||
@@ -149,7 +149,7 @@ export type DiagnosticEventInput = DiagnosticEventPayload extends infer Event
|
||||
let seq = 0;
|
||||
const listeners = new Set<(evt: DiagnosticEventPayload) => void>();
|
||||
|
||||
export function isDiagnosticsEnabled(config?: ClawdbotConfig): boolean {
|
||||
export function isDiagnosticsEnabled(config?: MoltbotConfig): boolean {
|
||||
return config?.diagnostics?.enabled === true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import { isDiagnosticFlagEnabled, resolveDiagnosticFlags } from "./diagnostic-flags.js";
|
||||
|
||||
describe("diagnostic flags", () => {
|
||||
it("merges config + env flags", () => {
|
||||
const cfg = {
|
||||
diagnostics: { flags: ["telegram.http", "cache.*"] },
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
const env = {
|
||||
CLAWDBOT_DIAGNOSTICS: "foo,bar",
|
||||
} as NodeJS.ProcessEnv;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
|
||||
const DIAGNOSTICS_ENV = "CLAWDBOT_DIAGNOSTICS";
|
||||
|
||||
@@ -32,7 +32,7 @@ function uniqueFlags(flags: string[]): string[] {
|
||||
}
|
||||
|
||||
export function resolveDiagnosticFlags(
|
||||
cfg?: ClawdbotConfig,
|
||||
cfg?: MoltbotConfig,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): string[] {
|
||||
const configFlags = Array.isArray(cfg?.diagnostics?.flags) ? cfg?.diagnostics?.flags : [];
|
||||
@@ -62,7 +62,7 @@ export function matchesDiagnosticFlag(flag: string, enabledFlags: string[]): boo
|
||||
|
||||
export function isDiagnosticFlagEnabled(
|
||||
flag: string,
|
||||
cfg?: ClawdbotConfig,
|
||||
cfg?: MoltbotConfig,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): boolean {
|
||||
const flags = resolveDiagnosticFlags(cfg, env);
|
||||
|
||||
@@ -16,7 +16,7 @@ describe("loadDotEnv", () => {
|
||||
const prevEnv = { ...process.env };
|
||||
const prevCwd = process.cwd();
|
||||
|
||||
const base = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-dotenv-test-"));
|
||||
const base = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-dotenv-test-"));
|
||||
const cwdDir = path.join(base, "cwd");
|
||||
const stateDir = path.join(base, "state");
|
||||
|
||||
@@ -48,7 +48,7 @@ describe("loadDotEnv", () => {
|
||||
const prevEnv = { ...process.env };
|
||||
const prevCwd = process.cwd();
|
||||
|
||||
const base = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-dotenv-test-"));
|
||||
const base = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-dotenv-test-"));
|
||||
const cwdDir = path.join(base, "cwd");
|
||||
const stateDir = path.join(base, "state");
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import { createExecApprovalForwarder } from "./exec-approval-forwarder.js";
|
||||
|
||||
const baseRequest = {
|
||||
@@ -24,7 +24,7 @@ describe("exec approval forwarder", () => {
|
||||
const deliver = vi.fn().mockResolvedValue([]);
|
||||
const cfg = {
|
||||
approvals: { exec: { enabled: true, mode: "session" } },
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const forwarder = createExecApprovalForwarder({
|
||||
getConfig: () => cfg,
|
||||
@@ -59,7 +59,7 @@ describe("exec approval forwarder", () => {
|
||||
targets: [{ channel: "telegram", to: "123" }],
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const forwarder = createExecApprovalForwarder({
|
||||
getConfig: () => cfg,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import { loadSessionStore, resolveStorePath } from "../config/sessions.js";
|
||||
import type {
|
||||
@@ -52,11 +52,11 @@ export type ExecApprovalForwarder = {
|
||||
};
|
||||
|
||||
export type ExecApprovalForwarderDeps = {
|
||||
getConfig?: () => ClawdbotConfig;
|
||||
getConfig?: () => MoltbotConfig;
|
||||
deliver?: typeof deliverOutboundPayloads;
|
||||
nowMs?: () => number;
|
||||
resolveSessionTarget?: (params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
request: ExecApprovalRequest;
|
||||
}) => ExecApprovalForwardTarget | null;
|
||||
};
|
||||
@@ -136,7 +136,7 @@ function buildExpiredMessage(request: ExecApprovalRequest) {
|
||||
}
|
||||
|
||||
function defaultResolveSessionTarget(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
request: ExecApprovalRequest;
|
||||
}): ExecApprovalForwardTarget | null {
|
||||
const sessionKey = params.request.request.sessionKey?.trim();
|
||||
@@ -159,7 +159,7 @@ function defaultResolveSessionTarget(params: {
|
||||
}
|
||||
|
||||
async function deliverToTargets(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
targets: ForwardTarget[];
|
||||
text: string;
|
||||
deliver: typeof deliverOutboundPayloads;
|
||||
|
||||
@@ -29,7 +29,7 @@ function makePathEnv(binDir: string): NodeJS.ProcessEnv {
|
||||
}
|
||||
|
||||
function makeTempDir() {
|
||||
return fs.mkdtempSync(path.join(os.tmpdir(), "clawdbot-exec-approvals-"));
|
||||
return fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-exec-approvals-"));
|
||||
}
|
||||
|
||||
describe("exec approvals allowlist matching", () => {
|
||||
|
||||
@@ -10,8 +10,8 @@ import { acquireGatewayLock, GatewayLockError } from "./gateway-lock.js";
|
||||
import { resolveConfigPath, resolveGatewayLockDir, resolveStateDir } from "../config/paths.js";
|
||||
|
||||
async function makeEnv() {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gateway-lock-"));
|
||||
const configPath = path.join(dir, "clawdbot.json");
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gateway-lock-"));
|
||||
const configPath = path.join(dir, "moltbot.json");
|
||||
await fs.writeFile(configPath, "{}", "utf8");
|
||||
await fs.mkdir(resolveGatewayLockDir(), { recursive: true });
|
||||
return {
|
||||
|
||||
@@ -81,7 +81,7 @@ function isGatewayArgv(args: string[]): boolean {
|
||||
}
|
||||
|
||||
const exe = normalized[0] ?? "";
|
||||
return exe.endsWith("/clawdbot") || exe === "clawdbot";
|
||||
return exe.endsWith("/moltbot") || exe === "moltbot";
|
||||
}
|
||||
|
||||
function readLinuxCmdline(pid: number): string[] | null {
|
||||
|
||||
@@ -3,7 +3,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import * as replyModule from "../auto-reply/reply.js";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import { resolveMainSessionKey } from "../config/sessions.js";
|
||||
import { runHeartbeatOnce } from "./heartbeat-runner.js";
|
||||
import { setActivePluginRegistry } from "../plugins/runtime.js";
|
||||
@@ -31,11 +31,11 @@ beforeEach(() => {
|
||||
|
||||
describe("resolveHeartbeatIntervalMs", () => {
|
||||
it("respects ackMaxChars for heartbeat acks", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
@@ -93,11 +93,11 @@ describe("resolveHeartbeatIntervalMs", () => {
|
||||
});
|
||||
|
||||
it("sends HEARTBEAT_OK when visibility.showOk is true", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
@@ -155,11 +155,11 @@ describe("resolveHeartbeatIntervalMs", () => {
|
||||
});
|
||||
|
||||
it("skips heartbeat LLM calls when visibility disables all output", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
@@ -222,11 +222,11 @@ describe("resolveHeartbeatIntervalMs", () => {
|
||||
});
|
||||
|
||||
it("skips delivery for markup-wrapped HEARTBEAT_OK", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
@@ -283,13 +283,13 @@ describe("resolveHeartbeatIntervalMs", () => {
|
||||
});
|
||||
|
||||
it("does not regress updatedAt when restoring heartbeat sessions", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const originalUpdatedAt = 1000;
|
||||
const bumpedUpdatedAt = 2000;
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
@@ -356,11 +356,11 @@ describe("resolveHeartbeatIntervalMs", () => {
|
||||
});
|
||||
|
||||
it("skips WhatsApp delivery when not linked or running", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
@@ -416,13 +416,13 @@ describe("resolveHeartbeatIntervalMs", () => {
|
||||
});
|
||||
|
||||
it("passes through accountId for telegram heartbeats", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
const prevTelegramToken = process.env.TELEGRAM_BOT_TOKEN;
|
||||
process.env.TELEGRAM_BOT_TOKEN = "";
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
@@ -484,13 +484,13 @@ describe("resolveHeartbeatIntervalMs", () => {
|
||||
});
|
||||
|
||||
it("does not pre-resolve telegram accountId (allows config-only account tokens)", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
const prevTelegramToken = process.env.TELEGRAM_BOT_TOKEN;
|
||||
process.env.TELEGRAM_BOT_TOKEN = "";
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from "node:path";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { HEARTBEAT_PROMPT } from "../auto-reply/heartbeat.js";
|
||||
import * as replyModule from "../auto-reply/reply.js";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import {
|
||||
resolveAgentIdFromSessionKey,
|
||||
resolveAgentMainSessionKey,
|
||||
@@ -95,7 +95,7 @@ describe("resolveHeartbeatPrompt", () => {
|
||||
});
|
||||
|
||||
it("uses a trimmed override when configured", () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: { defaults: { heartbeat: { prompt: " ping " } } },
|
||||
};
|
||||
expect(resolveHeartbeatPrompt(cfg)).toBe("ping");
|
||||
@@ -104,7 +104,7 @@ describe("resolveHeartbeatPrompt", () => {
|
||||
|
||||
describe("isHeartbeatEnabledForAgent", () => {
|
||||
it("enables only explicit heartbeat agents when configured", () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: { heartbeat: { every: "30m" } },
|
||||
list: [{ id: "main" }, { id: "ops", heartbeat: { every: "1h" } }],
|
||||
@@ -115,7 +115,7 @@ describe("isHeartbeatEnabledForAgent", () => {
|
||||
});
|
||||
|
||||
it("falls back to default agent when no explicit heartbeat entries", () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: { heartbeat: { every: "30m" } },
|
||||
list: [{ id: "main" }, { id: "ops" }],
|
||||
@@ -133,7 +133,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
};
|
||||
|
||||
it("respects target none", () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: { defaults: { heartbeat: { target: "none" } } },
|
||||
};
|
||||
expect(resolveHeartbeatDeliveryTarget({ cfg, entry: baseEntry })).toEqual({
|
||||
@@ -146,7 +146,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
it("uses last route by default", () => {
|
||||
const cfg: ClawdbotConfig = {};
|
||||
const cfg: MoltbotConfig = {};
|
||||
const entry = {
|
||||
...baseEntry,
|
||||
lastChannel: "whatsapp" as const,
|
||||
@@ -162,7 +162,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
it("normalizes explicit WhatsApp targets when allowFrom is '*'", () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
heartbeat: { target: "whatsapp", to: "whatsapp:(555) 123" },
|
||||
@@ -180,7 +180,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
it("skips when last route is webchat", () => {
|
||||
const cfg: ClawdbotConfig = {};
|
||||
const cfg: MoltbotConfig = {};
|
||||
const entry = {
|
||||
...baseEntry,
|
||||
lastChannel: "webchat" as const,
|
||||
@@ -196,7 +196,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
it("applies allowFrom fallback for WhatsApp targets", () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: { defaults: { heartbeat: { target: "whatsapp", to: "+1999" } } },
|
||||
channels: { whatsapp: { allowFrom: ["+1555", "+1666"] } },
|
||||
};
|
||||
@@ -216,7 +216,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
it("keeps WhatsApp group targets even with allowFrom set", () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
channels: { whatsapp: { allowFrom: ["+1555"] } },
|
||||
};
|
||||
const entry = {
|
||||
@@ -234,7 +234,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
it("normalizes prefixed WhatsApp group targets for heartbeat delivery", () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
channels: { whatsapp: { allowFrom: ["+1555"] } },
|
||||
};
|
||||
const entry = {
|
||||
@@ -252,7 +252,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
it("keeps explicit telegram targets", () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: { defaults: { heartbeat: { target: "telegram", to: "123" } } },
|
||||
};
|
||||
expect(resolveHeartbeatDeliveryTarget({ cfg, entry: baseEntry })).toEqual({
|
||||
@@ -265,7 +265,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
it("prefers per-agent heartbeat overrides when provided", () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: { defaults: { heartbeat: { target: "telegram", to: "123" } } },
|
||||
};
|
||||
const heartbeat = { target: "whatsapp", to: "+1555" } as const;
|
||||
@@ -287,7 +287,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
|
||||
describe("runHeartbeatOnce", () => {
|
||||
it("skips when agent heartbeat is not enabled", async () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: { heartbeat: { every: "30m" } },
|
||||
list: [{ id: "main" }, { id: "ops", heartbeat: { every: "1h" } }],
|
||||
@@ -302,7 +302,7 @@ describe("runHeartbeatOnce", () => {
|
||||
});
|
||||
|
||||
it("skips outside active hours", async () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
userTimezone: "UTC",
|
||||
@@ -326,11 +326,11 @@ describe("runHeartbeatOnce", () => {
|
||||
});
|
||||
|
||||
it("uses the last non-empty payload for delivery", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
@@ -384,11 +384,11 @@ describe("runHeartbeatOnce", () => {
|
||||
});
|
||||
|
||||
it("uses per-agent heartbeat overrides and session keys", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
heartbeat: { every: "30m", prompt: "Default prompt" },
|
||||
@@ -454,12 +454,12 @@ describe("runHeartbeatOnce", () => {
|
||||
});
|
||||
|
||||
it("runs heartbeats in the explicit session key when configured", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const groupId = "120363401234567890@g.us";
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
@@ -537,11 +537,11 @@ describe("runHeartbeatOnce", () => {
|
||||
});
|
||||
|
||||
it("suppresses duplicate heartbeat payloads within 24h", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
@@ -593,11 +593,11 @@ describe("runHeartbeatOnce", () => {
|
||||
});
|
||||
|
||||
it("can include reasoning payloads when enabled", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
@@ -665,11 +665,11 @@ describe("runHeartbeatOnce", () => {
|
||||
});
|
||||
|
||||
it("delivers reasoning even when the main heartbeat reply is HEARTBEAT_OK", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
@@ -736,11 +736,11 @@ describe("runHeartbeatOnce", () => {
|
||||
});
|
||||
|
||||
it("loads the default agent session from templated stores", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storeTemplate = path.join(tmpDir, "agents", "{agentId}", "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: { workspace: tmpDir, heartbeat: { every: "5m" } },
|
||||
list: [{ id: "work", default: true }],
|
||||
@@ -800,7 +800,7 @@ describe("runHeartbeatOnce", () => {
|
||||
});
|
||||
|
||||
it("skips heartbeat when HEARTBEAT.md is effectively empty (saves API calls)", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const workspaceDir = path.join(tmpDir, "workspace");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
@@ -814,7 +814,7 @@ describe("runHeartbeatOnce", () => {
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: workspaceDir,
|
||||
@@ -872,7 +872,7 @@ describe("runHeartbeatOnce", () => {
|
||||
});
|
||||
|
||||
it("runs heartbeat when HEARTBEAT.md has actionable content", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const workspaceDir = path.join(tmpDir, "workspace");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
@@ -886,7 +886,7 @@ describe("runHeartbeatOnce", () => {
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: workspaceDir,
|
||||
@@ -942,7 +942,7 @@ describe("runHeartbeatOnce", () => {
|
||||
});
|
||||
|
||||
it("runs heartbeat when HEARTBEAT.md does not exist (lets LLM decide)", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const workspaceDir = path.join(tmpDir, "workspace");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
@@ -950,7 +950,7 @@ describe("runHeartbeatOnce", () => {
|
||||
await fs.mkdir(workspaceDir, { recursive: true });
|
||||
// Don't create HEARTBEAT.md - it doesn't exist
|
||||
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: workspaceDir,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import { startHeartbeatRunner } from "./heartbeat-runner.js";
|
||||
|
||||
describe("startHeartbeatRunner", () => {
|
||||
@@ -17,7 +17,7 @@ describe("startHeartbeatRunner", () => {
|
||||
const runner = startHeartbeatRunner({
|
||||
cfg: {
|
||||
agents: { defaults: { heartbeat: { every: "30m" } } },
|
||||
} as ClawdbotConfig,
|
||||
} as MoltbotConfig,
|
||||
runOnce: runSpy,
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ describe("startHeartbeatRunner", () => {
|
||||
{ id: "ops", heartbeat: { every: "15m" } },
|
||||
],
|
||||
},
|
||||
} as ClawdbotConfig);
|
||||
} as MoltbotConfig);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(10 * 60_000 + 1_000);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from "node:path";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import * as replyModule from "../auto-reply/reply.js";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import { resolveMainSessionKey } from "../config/sessions.js";
|
||||
import { setActivePluginRegistry } from "../plugins/runtime.js";
|
||||
import { createPluginRuntime } from "../plugins/runtime/index.js";
|
||||
@@ -36,11 +36,11 @@ beforeEach(() => {
|
||||
|
||||
describe("runHeartbeatOnce", () => {
|
||||
it("uses the delivery target as sender when lastTo differs", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: tmpDir,
|
||||
|
||||
@@ -22,7 +22,7 @@ import type { ReplyPayload } from "../auto-reply/types.js";
|
||||
import { getChannelPlugin } from "../channels/plugins/index.js";
|
||||
import type { ChannelHeartbeatDeps } from "../channels/plugins/types.js";
|
||||
import { parseDurationMs } from "../cli/parse-duration.js";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import {
|
||||
canonicalizeMainSessionAlias,
|
||||
@@ -97,7 +97,7 @@ const EXEC_EVENT_PROMPT =
|
||||
"Please relay the command output to the user in a helpful way. If the command succeeded, share the relevant output. " +
|
||||
"If it failed, explain what went wrong.";
|
||||
|
||||
function resolveActiveHoursTimezone(cfg: ClawdbotConfig, raw?: string): string {
|
||||
function resolveActiveHoursTimezone(cfg: MoltbotConfig, raw?: string): string {
|
||||
const trimmed = raw?.trim();
|
||||
if (!trimmed || trimmed === "user") {
|
||||
return resolveUserTimezone(cfg.agents?.defaults?.userTimezone);
|
||||
@@ -149,7 +149,7 @@ function resolveMinutesInTimeZone(nowMs: number, timeZone: string): number | nul
|
||||
}
|
||||
|
||||
function isWithinActiveHours(
|
||||
cfg: ClawdbotConfig,
|
||||
cfg: MoltbotConfig,
|
||||
heartbeat?: HeartbeatConfig,
|
||||
nowMs?: number,
|
||||
): boolean {
|
||||
@@ -181,15 +181,15 @@ type HeartbeatAgentState = {
|
||||
|
||||
export type HeartbeatRunner = {
|
||||
stop: () => void;
|
||||
updateConfig: (cfg: ClawdbotConfig) => void;
|
||||
updateConfig: (cfg: MoltbotConfig) => void;
|
||||
};
|
||||
|
||||
function hasExplicitHeartbeatAgents(cfg: ClawdbotConfig) {
|
||||
function hasExplicitHeartbeatAgents(cfg: MoltbotConfig) {
|
||||
const list = cfg.agents?.list ?? [];
|
||||
return list.some((entry) => Boolean(entry?.heartbeat));
|
||||
}
|
||||
|
||||
export function isHeartbeatEnabledForAgent(cfg: ClawdbotConfig, agentId?: string): boolean {
|
||||
export function isHeartbeatEnabledForAgent(cfg: MoltbotConfig, agentId?: string): boolean {
|
||||
const resolvedAgentId = normalizeAgentId(agentId ?? resolveDefaultAgentId(cfg));
|
||||
const list = cfg.agents?.list ?? [];
|
||||
const hasExplicit = hasExplicitHeartbeatAgents(cfg);
|
||||
@@ -201,10 +201,7 @@ export function isHeartbeatEnabledForAgent(cfg: ClawdbotConfig, agentId?: string
|
||||
return resolvedAgentId === resolveDefaultAgentId(cfg);
|
||||
}
|
||||
|
||||
function resolveHeartbeatConfig(
|
||||
cfg: ClawdbotConfig,
|
||||
agentId?: string,
|
||||
): HeartbeatConfig | undefined {
|
||||
function resolveHeartbeatConfig(cfg: MoltbotConfig, agentId?: string): HeartbeatConfig | undefined {
|
||||
const defaults = cfg.agents?.defaults?.heartbeat;
|
||||
if (!agentId) return defaults;
|
||||
const overrides = resolveAgentConfig(cfg, agentId)?.heartbeat;
|
||||
@@ -213,7 +210,7 @@ function resolveHeartbeatConfig(
|
||||
}
|
||||
|
||||
export function resolveHeartbeatSummaryForAgent(
|
||||
cfg: ClawdbotConfig,
|
||||
cfg: MoltbotConfig,
|
||||
agentId?: string,
|
||||
): HeartbeatSummary {
|
||||
const defaults = cfg.agents?.defaults?.heartbeat;
|
||||
@@ -260,7 +257,7 @@ export function resolveHeartbeatSummaryForAgent(
|
||||
};
|
||||
}
|
||||
|
||||
function resolveHeartbeatAgents(cfg: ClawdbotConfig): HeartbeatAgent[] {
|
||||
function resolveHeartbeatAgents(cfg: MoltbotConfig): HeartbeatAgent[] {
|
||||
const list = cfg.agents?.list ?? [];
|
||||
if (hasExplicitHeartbeatAgents(cfg)) {
|
||||
return list
|
||||
@@ -276,7 +273,7 @@ function resolveHeartbeatAgents(cfg: ClawdbotConfig): HeartbeatAgent[] {
|
||||
}
|
||||
|
||||
export function resolveHeartbeatIntervalMs(
|
||||
cfg: ClawdbotConfig,
|
||||
cfg: MoltbotConfig,
|
||||
overrideEvery?: string,
|
||||
heartbeat?: HeartbeatConfig,
|
||||
) {
|
||||
@@ -298,11 +295,11 @@ export function resolveHeartbeatIntervalMs(
|
||||
return ms;
|
||||
}
|
||||
|
||||
export function resolveHeartbeatPrompt(cfg: ClawdbotConfig, heartbeat?: HeartbeatConfig) {
|
||||
export function resolveHeartbeatPrompt(cfg: MoltbotConfig, heartbeat?: HeartbeatConfig) {
|
||||
return resolveHeartbeatPromptText(heartbeat?.prompt ?? cfg.agents?.defaults?.heartbeat?.prompt);
|
||||
}
|
||||
|
||||
function resolveHeartbeatAckMaxChars(cfg: ClawdbotConfig, heartbeat?: HeartbeatConfig) {
|
||||
function resolveHeartbeatAckMaxChars(cfg: MoltbotConfig, heartbeat?: HeartbeatConfig) {
|
||||
return Math.max(
|
||||
0,
|
||||
heartbeat?.ackMaxChars ??
|
||||
@@ -312,7 +309,7 @@ function resolveHeartbeatAckMaxChars(cfg: ClawdbotConfig, heartbeat?: HeartbeatC
|
||||
}
|
||||
|
||||
function resolveHeartbeatSession(
|
||||
cfg: ClawdbotConfig,
|
||||
cfg: MoltbotConfig,
|
||||
agentId?: string,
|
||||
heartbeat?: HeartbeatConfig,
|
||||
) {
|
||||
@@ -431,7 +428,7 @@ function normalizeHeartbeatReply(
|
||||
}
|
||||
|
||||
export async function runHeartbeatOnce(opts: {
|
||||
cfg?: ClawdbotConfig;
|
||||
cfg?: MoltbotConfig;
|
||||
agentId?: string;
|
||||
heartbeat?: HeartbeatConfig;
|
||||
reason?: string;
|
||||
@@ -758,7 +755,7 @@ export async function runHeartbeatOnce(opts: {
|
||||
}
|
||||
|
||||
export function startHeartbeatRunner(opts: {
|
||||
cfg?: ClawdbotConfig;
|
||||
cfg?: MoltbotConfig;
|
||||
runtime?: RuntimeEnv;
|
||||
abortSignal?: AbortSignal;
|
||||
runOnce?: typeof runHeartbeatOnce;
|
||||
@@ -804,7 +801,7 @@ export function startHeartbeatRunner(opts: {
|
||||
state.timer.unref?.();
|
||||
};
|
||||
|
||||
const updateConfig = (cfg: ClawdbotConfig) => {
|
||||
const updateConfig = (cfg: MoltbotConfig) => {
|
||||
if (state.stopped) return;
|
||||
const now = Date.now();
|
||||
const prevAgents = state.agents;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import { resolveHeartbeatVisibility } from "./heartbeat-visibility.js";
|
||||
|
||||
describe("resolveHeartbeatVisibility", () => {
|
||||
it("returns default values when no config is provided", () => {
|
||||
const cfg = {} as ClawdbotConfig;
|
||||
const cfg = {} as MoltbotConfig;
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "telegram" });
|
||||
|
||||
expect(result).toEqual({
|
||||
@@ -25,7 +25,7 @@ describe("resolveHeartbeatVisibility", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "telegram" });
|
||||
|
||||
@@ -52,7 +52,7 @@ describe("resolveHeartbeatVisibility", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "telegram" });
|
||||
|
||||
@@ -88,7 +88,7 @@ describe("resolveHeartbeatVisibility", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({
|
||||
cfg,
|
||||
@@ -120,7 +120,7 @@ describe("resolveHeartbeatVisibility", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({
|
||||
cfg,
|
||||
@@ -151,7 +151,7 @@ describe("resolveHeartbeatVisibility", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "telegram" });
|
||||
|
||||
@@ -174,7 +174,7 @@ describe("resolveHeartbeatVisibility", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({
|
||||
cfg,
|
||||
@@ -195,7 +195,7 @@ describe("resolveHeartbeatVisibility", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "whatsapp" });
|
||||
|
||||
@@ -215,7 +215,7 @@ describe("resolveHeartbeatVisibility", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "discord" });
|
||||
|
||||
@@ -237,7 +237,7 @@ describe("resolveHeartbeatVisibility", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "slack" });
|
||||
|
||||
@@ -259,7 +259,7 @@ describe("resolveHeartbeatVisibility", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "webchat" });
|
||||
|
||||
@@ -271,7 +271,7 @@ describe("resolveHeartbeatVisibility", () => {
|
||||
});
|
||||
|
||||
it("webchat returns defaults when no channel defaults configured", () => {
|
||||
const cfg = {} as ClawdbotConfig;
|
||||
const cfg = {} as MoltbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({ cfg, channel: "webchat" });
|
||||
|
||||
@@ -291,7 +291,7 @@ describe("resolveHeartbeatVisibility", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = resolveHeartbeatVisibility({
|
||||
cfg,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import type { ChannelHeartbeatVisibilityConfig } from "../config/types.channels.js";
|
||||
import type { GatewayMessageChannel } from "../utils/message-channel.js";
|
||||
|
||||
@@ -20,7 +20,7 @@ const DEFAULT_VISIBILITY: ResolvedHeartbeatVisibility = {
|
||||
* For webchat, uses channels.defaults.heartbeat since webchat doesn't have per-channel config.
|
||||
*/
|
||||
export function resolveHeartbeatVisibility(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: GatewayMessageChannel;
|
||||
accountId?: string;
|
||||
}): ResolvedHeartbeatVisibility {
|
||||
|
||||
@@ -28,7 +28,7 @@ describe("isMainModule", () => {
|
||||
it("returns false when running under PM2 but this module is imported", () => {
|
||||
expect(
|
||||
isMainModule({
|
||||
currentFile: "/repo/node_modules/clawdbot/dist/index.js",
|
||||
currentFile: "/repo/node_modules/moltbot/dist/index.js",
|
||||
argv: ["node", "/repo/app.js"],
|
||||
cwd: "/repo",
|
||||
env: { pm_exec_path: "/repo/app.js", pm_id: "0" },
|
||||
|
||||
@@ -24,7 +24,7 @@ function fallbackHostName() {
|
||||
os
|
||||
.hostname()
|
||||
.replace(/\.local$/i, "")
|
||||
.trim() || "clawdbot"
|
||||
.trim() || "moltbot"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const CORE_PACKAGE_NAMES = new Set(["moltbot", "clawdbot"]);
|
||||
const CORE_PACKAGE_NAMES = new Set(["moltbot", "moltbot"]);
|
||||
|
||||
async function readPackageName(dir: string): Promise<string | null> {
|
||||
try {
|
||||
@@ -39,7 +39,7 @@ function candidateDirsFromArgv1(argv1: string): string[] {
|
||||
return candidates;
|
||||
}
|
||||
|
||||
export async function resolveClawdbotPackageRoot(opts: {
|
||||
export async function resolveMoltbotPackageRoot(opts: {
|
||||
cwd?: string;
|
||||
argv1?: string;
|
||||
moduleUrl?: string;
|
||||
@@ -12,7 +12,7 @@ vi.mock("./targets.js", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import { resolveAgentDeliveryPlan, resolveAgentOutboundTarget } from "./agent-delivery.js";
|
||||
|
||||
describe("agent delivery helpers", () => {
|
||||
@@ -45,7 +45,7 @@ describe("agent delivery helpers", () => {
|
||||
});
|
||||
|
||||
const resolved = resolveAgentOutboundTarget({
|
||||
cfg: {} as ClawdbotConfig,
|
||||
cfg: {} as MoltbotConfig,
|
||||
plan,
|
||||
targetMode: "implicit",
|
||||
});
|
||||
@@ -68,7 +68,7 @@ describe("agent delivery helpers", () => {
|
||||
|
||||
mocks.resolveOutboundTarget.mockClear();
|
||||
const resolved = resolveAgentOutboundTarget({
|
||||
cfg: {} as ClawdbotConfig,
|
||||
cfg: {} as MoltbotConfig,
|
||||
plan,
|
||||
targetMode: "explicit",
|
||||
validateExplicitTarget: false,
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
resolveSessionDeliveryTarget,
|
||||
type SessionDeliveryTarget,
|
||||
} from "./targets.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import type { OutboundTargetResolution } from "./targets.js";
|
||||
|
||||
export type AgentDeliveryPlan = {
|
||||
@@ -98,7 +98,7 @@ export function resolveAgentDeliveryPlan(params: {
|
||||
}
|
||||
|
||||
export function resolveAgentOutboundTarget(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
plan: AgentDeliveryPlan;
|
||||
targetMode?: ChannelOutboundTargetMode;
|
||||
validateExplicitTarget?: boolean;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { listChannelPlugins } from "../../channels/plugins/index.js";
|
||||
import type { ChannelPlugin } from "../../channels/plugins/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import {
|
||||
listDeliverableMessageChannels,
|
||||
type DeliverableMessageChannel,
|
||||
@@ -21,7 +21,7 @@ function isAccountEnabled(account: unknown): boolean {
|
||||
return enabled !== false;
|
||||
}
|
||||
|
||||
async function isPluginConfigured(plugin: ChannelPlugin, cfg: ClawdbotConfig): Promise<boolean> {
|
||||
async function isPluginConfigured(plugin: ChannelPlugin, cfg: MoltbotConfig): Promise<boolean> {
|
||||
const accountIds = plugin.config.listAccountIds(cfg);
|
||||
if (accountIds.length === 0) return false;
|
||||
|
||||
@@ -40,7 +40,7 @@ async function isPluginConfigured(plugin: ChannelPlugin, cfg: ClawdbotConfig): P
|
||||
}
|
||||
|
||||
export async function listConfiguredMessageChannels(
|
||||
cfg: ClawdbotConfig,
|
||||
cfg: MoltbotConfig,
|
||||
): Promise<MessageChannelId[]> {
|
||||
const channels: MessageChannelId[] = [];
|
||||
for (const plugin of listChannelPlugins()) {
|
||||
@@ -53,7 +53,7 @@ export async function listConfiguredMessageChannels(
|
||||
}
|
||||
|
||||
export async function resolveMessageChannelSelection(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel?: string | null;
|
||||
}): Promise<{ channel: MessageChannelId; configured: MessageChannelId[] }> {
|
||||
const normalized = normalizeMessageChannel(params.channel);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import { signalOutbound } from "../../channels/plugins/outbound/signal.js";
|
||||
import { telegramOutbound } from "../../channels/plugins/outbound/telegram.js";
|
||||
import { whatsappOutbound } from "../../channels/plugins/outbound/whatsapp.js";
|
||||
@@ -38,7 +38,7 @@ describe("deliverOutboundPayloads", () => {
|
||||
});
|
||||
it("chunks telegram markdown and passes through accountId", async () => {
|
||||
const sendTelegram = vi.fn().mockResolvedValue({ messageId: "m1", chatId: "c1" });
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
channels: { telegram: { botToken: "tok-1", textChunkLimit: 2 } },
|
||||
};
|
||||
const prevTelegramToken = process.env.TELEGRAM_BOT_TOKEN;
|
||||
@@ -71,7 +71,7 @@ describe("deliverOutboundPayloads", () => {
|
||||
|
||||
it("passes explicit accountId to sendTelegram", async () => {
|
||||
const sendTelegram = vi.fn().mockResolvedValue({ messageId: "m1", chatId: "c1" });
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
channels: { telegram: { botToken: "tok-1", textChunkLimit: 2 } },
|
||||
};
|
||||
|
||||
@@ -93,7 +93,7 @@ describe("deliverOutboundPayloads", () => {
|
||||
|
||||
it("uses signal media maxBytes from config", async () => {
|
||||
const sendSignal = vi.fn().mockResolvedValue({ messageId: "s1", timestamp: 123 });
|
||||
const cfg: ClawdbotConfig = { channels: { signal: { mediaMaxMb: 2 } } };
|
||||
const cfg: MoltbotConfig = { channels: { signal: { mediaMaxMb: 2 } } };
|
||||
|
||||
const results = await deliverOutboundPayloads({
|
||||
cfg,
|
||||
@@ -118,7 +118,7 @@ describe("deliverOutboundPayloads", () => {
|
||||
|
||||
it("chunks Signal markdown using the format-first chunker", async () => {
|
||||
const sendSignal = vi.fn().mockResolvedValue({ messageId: "s1", timestamp: 123 });
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
channels: { signal: { textChunkLimit: 20 } },
|
||||
};
|
||||
const text = `Intro\\n\\n\`\`\`\`md\\n${"y".repeat(60)}\\n\`\`\`\\n\\nOutro`;
|
||||
@@ -152,7 +152,7 @@ describe("deliverOutboundPayloads", () => {
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ messageId: "w1", toJid: "jid" })
|
||||
.mockResolvedValueOnce({ messageId: "w2", toJid: "jid" });
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
channels: { whatsapp: { textChunkLimit: 2 } },
|
||||
};
|
||||
|
||||
@@ -170,7 +170,7 @@ describe("deliverOutboundPayloads", () => {
|
||||
|
||||
it("respects newline chunk mode for WhatsApp", async () => {
|
||||
const sendWhatsApp = vi.fn().mockResolvedValue({ messageId: "w1", toJid: "jid" });
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
channels: { whatsapp: { textChunkLimit: 4000, chunkMode: "newline" } },
|
||||
};
|
||||
|
||||
@@ -229,7 +229,7 @@ describe("deliverOutboundPayloads", () => {
|
||||
]),
|
||||
);
|
||||
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
channels: { matrix: { textChunkLimit: 4000, chunkMode: "newline" } },
|
||||
};
|
||||
const text = "```js\nconst a = 1;\nconst b = 2;\n```\nAfter";
|
||||
@@ -256,7 +256,7 @@ describe("deliverOutboundPayloads", () => {
|
||||
},
|
||||
]),
|
||||
);
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
agents: { defaults: { mediaMaxMb: 3 } },
|
||||
};
|
||||
|
||||
@@ -293,7 +293,7 @@ describe("deliverOutboundPayloads", () => {
|
||||
.mockRejectedValueOnce(new Error("fail"))
|
||||
.mockResolvedValueOnce({ messageId: "w2", toJid: "jid" });
|
||||
const onError = vi.fn();
|
||||
const cfg: ClawdbotConfig = {};
|
||||
const cfg: MoltbotConfig = {};
|
||||
|
||||
const results = await deliverOutboundPayloads({
|
||||
cfg,
|
||||
@@ -313,7 +313,7 @@ describe("deliverOutboundPayloads", () => {
|
||||
it("passes normalized payload to onError", async () => {
|
||||
const sendWhatsApp = vi.fn().mockRejectedValue(new Error("boom"));
|
||||
const onError = vi.fn();
|
||||
const cfg: ClawdbotConfig = {};
|
||||
const cfg: MoltbotConfig = {};
|
||||
|
||||
await deliverOutboundPayloads({
|
||||
cfg,
|
||||
@@ -334,7 +334,7 @@ describe("deliverOutboundPayloads", () => {
|
||||
|
||||
it("mirrors delivered output when mirror options are provided", async () => {
|
||||
const sendTelegram = vi.fn().mockResolvedValue({ messageId: "m1", chatId: "c1" });
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
channels: { telegram: { botToken: "tok-1", textChunkLimit: 2 } },
|
||||
};
|
||||
mocks.appendAssistantMessageToSessionTranscript.mockClear();
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { ReplyPayload } from "../../auto-reply/types.js";
|
||||
import { resolveChannelMediaMaxBytes } from "../../channels/plugins/media-limits.js";
|
||||
import { loadChannelOutboundAdapter } from "../../channels/plugins/outbound/load.js";
|
||||
import type { ChannelOutboundAdapter } from "../../channels/plugins/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import { resolveMarkdownTableMode } from "../../config/markdown-tables.js";
|
||||
import type { sendMessageDiscord } from "../../discord/send.js";
|
||||
import type { sendMessageIMessage } from "../../imessage/send.js";
|
||||
@@ -82,7 +82,7 @@ function throwIfAborted(abortSignal?: AbortSignal): void {
|
||||
|
||||
// Channel docking: outbound delivery delegates to plugin.outbound adapters.
|
||||
async function createChannelHandler(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: Exclude<OutboundChannel, "none">;
|
||||
to: string;
|
||||
accountId?: string;
|
||||
@@ -114,7 +114,7 @@ async function createChannelHandler(params: {
|
||||
|
||||
function createPluginHandler(params: {
|
||||
outbound?: ChannelOutboundAdapter;
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: Exclude<OutboundChannel, "none">;
|
||||
to: string;
|
||||
accountId?: string;
|
||||
@@ -175,7 +175,7 @@ function createPluginHandler(params: {
|
||||
}
|
||||
|
||||
export async function deliverOutboundPayloads(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: Exclude<OutboundChannel, "none">;
|
||||
to: string;
|
||||
accountId?: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ChannelDirectoryEntryKind, ChannelId } from "../../channels/plugins/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
|
||||
type CacheEntry<T> = {
|
||||
value: T;
|
||||
@@ -21,11 +21,11 @@ export function buildDirectoryCacheKey(key: DirectoryCacheKey): string {
|
||||
|
||||
export class DirectoryCache<T> {
|
||||
private readonly cache = new Map<string, CacheEntry<T>>();
|
||||
private lastConfigRef: ClawdbotConfig | null = null;
|
||||
private lastConfigRef: MoltbotConfig | null = null;
|
||||
|
||||
constructor(private readonly ttlMs: number) {}
|
||||
|
||||
get(key: string, cfg: ClawdbotConfig): T | undefined {
|
||||
get(key: string, cfg: MoltbotConfig): T | undefined {
|
||||
this.resetIfConfigChanged(cfg);
|
||||
const entry = this.cache.get(key);
|
||||
if (!entry) return undefined;
|
||||
@@ -36,7 +36,7 @@ export class DirectoryCache<T> {
|
||||
return entry.value;
|
||||
}
|
||||
|
||||
set(key: string, value: T, cfg: ClawdbotConfig): void {
|
||||
set(key: string, value: T, cfg: MoltbotConfig): void {
|
||||
this.resetIfConfigChanged(cfg);
|
||||
this.cache.set(key, { value, fetchedAt: Date.now() });
|
||||
}
|
||||
@@ -47,12 +47,12 @@ export class DirectoryCache<T> {
|
||||
}
|
||||
}
|
||||
|
||||
clear(cfg?: ClawdbotConfig): void {
|
||||
clear(cfg?: MoltbotConfig): void {
|
||||
this.cache.clear();
|
||||
if (cfg) this.lastConfigRef = cfg;
|
||||
}
|
||||
|
||||
private resetIfConfigChanged(cfg: ClawdbotConfig): void {
|
||||
private resetIfConfigChanged(cfg: MoltbotConfig): void {
|
||||
if (this.lastConfigRef && this.lastConfigRef !== cfg) {
|
||||
this.cache.clear();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import { setActivePluginRegistry } from "../../plugins/runtime.js";
|
||||
import { createIMessageTestPlugin, createTestRegistry } from "../../test-utils/channel-plugins.js";
|
||||
import { slackPlugin } from "../../../extensions/slack/src/channel.js";
|
||||
@@ -26,7 +26,7 @@ const slackConfig = {
|
||||
appToken: "xapp-test",
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const whatsappConfig = {
|
||||
channels: {
|
||||
@@ -34,7 +34,7 @@ const whatsappConfig = {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
describe("runMessageAction context isolation", () => {
|
||||
beforeEach(async () => {
|
||||
@@ -263,7 +263,7 @@ describe("runMessageAction context isolation", () => {
|
||||
token: "tg-test",
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = await runMessageAction({
|
||||
cfg: multiConfig,
|
||||
@@ -305,7 +305,7 @@ describe("runMessageAction context isolation", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
await expect(
|
||||
runMessageAction({
|
||||
@@ -423,7 +423,7 @@ describe("runMessageAction sendAttachment hydration", () => {
|
||||
password: "test-password",
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const result = await runMessageAction({
|
||||
cfg,
|
||||
@@ -491,7 +491,7 @@ describe("runMessageAction accountId defaults", () => {
|
||||
|
||||
it("propagates defaultAccountId into params", async () => {
|
||||
await runMessageAction({
|
||||
cfg: {} as ClawdbotConfig,
|
||||
cfg: {} as MoltbotConfig,
|
||||
action: "send",
|
||||
params: {
|
||||
channel: "discord",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import { setActivePluginRegistry } from "../../plugins/runtime.js";
|
||||
import { createTestRegistry } from "../../test-utils/channel-plugins.js";
|
||||
import { slackPlugin } from "../../../extensions/slack/src/channel.js";
|
||||
@@ -39,7 +39,7 @@ const slackConfig = {
|
||||
appToken: "xapp-test",
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
describe("runMessageAction Slack threading", () => {
|
||||
beforeEach(async () => {
|
||||
|
||||
@@ -15,7 +15,7 @@ import type {
|
||||
ChannelMessageActionName,
|
||||
ChannelThreadingToolContext,
|
||||
} from "../../channels/plugins/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import {
|
||||
isDeliverableMessageChannel,
|
||||
normalizeMessageChannel,
|
||||
@@ -54,7 +54,7 @@ export type MessageActionRunnerGateway = {
|
||||
};
|
||||
|
||||
export type RunMessageActionParams = {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
action: ChannelMessageActionName;
|
||||
params: Record<string, unknown>;
|
||||
defaultAccountId?: string;
|
||||
@@ -168,7 +168,7 @@ function applyCrossContextMessageDecoration({
|
||||
}
|
||||
|
||||
async function maybeApplyCrossContextMarker(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
action: ChannelMessageActionName;
|
||||
target: string;
|
||||
@@ -224,7 +224,7 @@ function resolveSlackAutoThreadId(params: {
|
||||
}
|
||||
|
||||
function resolveAttachmentMaxBytes(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
accountId?: string | null;
|
||||
}): number | undefined {
|
||||
@@ -298,7 +298,7 @@ function normalizeBase64Payload(params: { base64?: string; contentType?: string
|
||||
}
|
||||
|
||||
async function hydrateSetGroupIconParams(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
accountId?: string | null;
|
||||
args: Record<string, unknown>;
|
||||
@@ -355,7 +355,7 @@ async function hydrateSetGroupIconParams(params: {
|
||||
}
|
||||
|
||||
async function hydrateSendAttachmentParams(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
accountId?: string | null;
|
||||
args: Record<string, unknown>;
|
||||
@@ -444,7 +444,7 @@ function parseCardParam(params: Record<string, unknown>): void {
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveChannel(cfg: ClawdbotConfig, params: Record<string, unknown>) {
|
||||
async function resolveChannel(cfg: MoltbotConfig, params: Record<string, unknown>) {
|
||||
const channelHint = readStringParam(params, "channel");
|
||||
const selection = await resolveMessageChannelSelection({
|
||||
cfg,
|
||||
@@ -454,7 +454,7 @@ async function resolveChannel(cfg: ClawdbotConfig, params: Record<string, unknow
|
||||
}
|
||||
|
||||
async function resolveActionTarget(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
action: ChannelMessageActionName;
|
||||
args: Record<string, unknown>;
|
||||
@@ -499,7 +499,7 @@ async function resolveActionTarget(params: {
|
||||
}
|
||||
|
||||
type ResolvedActionContext = {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
params: Record<string, unknown>;
|
||||
channel: ChannelId;
|
||||
accountId?: string | null;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getChannelPlugin, normalizeChannelId } from "../../channels/plugins/index.js";
|
||||
import type { ChannelId } from "../../channels/plugins/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import { callGateway, randomIdempotencyKey } from "../../gateway/call.js";
|
||||
import type { PollInput } from "../../polls.js";
|
||||
@@ -41,7 +41,7 @@ type MessageSendParams = {
|
||||
dryRun?: boolean;
|
||||
bestEffort?: boolean;
|
||||
deps?: OutboundSendDeps;
|
||||
cfg?: ClawdbotConfig;
|
||||
cfg?: MoltbotConfig;
|
||||
gateway?: MessageGatewayOptions;
|
||||
idempotencyKey?: string;
|
||||
mirror?: {
|
||||
@@ -71,7 +71,7 @@ type MessagePollParams = {
|
||||
durationHours?: number;
|
||||
channel?: string;
|
||||
dryRun?: boolean;
|
||||
cfg?: ClawdbotConfig;
|
||||
cfg?: MoltbotConfig;
|
||||
gateway?: MessageGatewayOptions;
|
||||
idempotencyKey?: string;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import {
|
||||
applyCrossContextDecoration,
|
||||
buildCrossContextDecoration,
|
||||
@@ -14,13 +14,13 @@ const slackConfig = {
|
||||
appToken: "xapp-test",
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const discordConfig = {
|
||||
channels: {
|
||||
discord: {},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
describe("outbound policy", () => {
|
||||
it("blocks cross-provider sends by default", () => {
|
||||
@@ -41,7 +41,7 @@ describe("outbound policy", () => {
|
||||
tools: {
|
||||
message: { crossContext: { allowAcrossProviders: true } },
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
expect(() =>
|
||||
enforceCrossContextPolicy({
|
||||
@@ -58,7 +58,7 @@ describe("outbound policy", () => {
|
||||
const cfg = {
|
||||
...slackConfig,
|
||||
tools: { message: { crossContext: { allowWithinProvider: false } } },
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
expect(() =>
|
||||
enforceCrossContextPolicy({
|
||||
|
||||
@@ -4,7 +4,7 @@ import type {
|
||||
ChannelMessageActionName,
|
||||
ChannelThreadingToolContext,
|
||||
} from "../../channels/plugins/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import { getChannelMessageAdapter } from "./channel-adapters.js";
|
||||
import { formatTargetDisplay, lookupDirectoryDisplay } from "./target-resolver.js";
|
||||
|
||||
@@ -74,7 +74,7 @@ export function enforceCrossContextPolicy(params: {
|
||||
action: ChannelMessageActionName;
|
||||
args: Record<string, unknown>;
|
||||
toolContext?: ChannelThreadingToolContext;
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
}): void {
|
||||
const currentTarget = params.toolContext?.currentChannelId?.trim();
|
||||
if (!currentTarget) return;
|
||||
@@ -112,7 +112,7 @@ export function enforceCrossContextPolicy(params: {
|
||||
}
|
||||
|
||||
export async function buildCrossContextDecoration(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
target: string;
|
||||
toolContext?: ChannelThreadingToolContext;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
||||
import { dispatchChannelMessageAction } from "../../channels/plugins/message-actions.js";
|
||||
import type { ChannelId, ChannelThreadingToolContext } from "../../channels/plugins/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import { appendAssistantMessageToSessionTranscript } from "../../config/sessions.js";
|
||||
import type { GatewayClientMode, GatewayClientName } from "../../utils/message-channel.js";
|
||||
import type { OutboundSendDeps } from "./deliver.js";
|
||||
@@ -18,7 +18,7 @@ export type OutboundGatewayContext = {
|
||||
};
|
||||
|
||||
export type OutboundSendContext = {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
params: Record<string, unknown>;
|
||||
accountId?: string | null;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import { resolveOutboundSessionRoute } from "./outbound-session.js";
|
||||
|
||||
const baseConfig = {} as ClawdbotConfig;
|
||||
const baseConfig = {} as MoltbotConfig;
|
||||
|
||||
describe("resolveOutboundSessionRoute", () => {
|
||||
it("builds Slack thread session keys", async () => {
|
||||
@@ -36,7 +36,7 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
});
|
||||
|
||||
it("treats Telegram usernames as DMs when unresolved", async () => {
|
||||
const cfg = { session: { dmScope: "per-channel-peer" } } as ClawdbotConfig;
|
||||
const cfg = { session: { dmScope: "per-channel-peer" } } as MoltbotConfig;
|
||||
const route = await resolveOutboundSessionRoute({
|
||||
cfg,
|
||||
channel: "telegram",
|
||||
@@ -56,7 +56,7 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
alice: ["discord:123"],
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const route = await resolveOutboundSessionRoute({
|
||||
cfg,
|
||||
@@ -81,7 +81,7 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
});
|
||||
|
||||
it("treats Zalo Personal DM targets as direct sessions", async () => {
|
||||
const cfg = { session: { dmScope: "per-channel-peer" } } as ClawdbotConfig;
|
||||
const cfg = { session: { dmScope: "per-channel-peer" } } as MoltbotConfig;
|
||||
const route = await resolveOutboundSessionRoute({
|
||||
cfg,
|
||||
channel: "zalouser",
|
||||
@@ -102,7 +102,7 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const route = await resolveOutboundSessionRoute({
|
||||
cfg,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { MsgContext } from "../../auto-reply/templating.js";
|
||||
import { getChannelPlugin } from "../../channels/plugins/index.js";
|
||||
import type { ChannelId } from "../../channels/plugins/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import { recordSessionMetaFromInbound, resolveStorePath } from "../../config/sessions.js";
|
||||
import { parseDiscordTarget } from "../../discord/targets.js";
|
||||
import { parseIMessageTarget, normalizeIMessageHandle } from "../../imessage/targets.js";
|
||||
@@ -37,7 +37,7 @@ export type OutboundSessionRoute = {
|
||||
};
|
||||
|
||||
export type ResolveOutboundSessionRouteParams = {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
agentId: string;
|
||||
accountId?: string | null;
|
||||
@@ -100,7 +100,7 @@ function inferPeerKind(params: {
|
||||
}
|
||||
|
||||
function buildBaseSessionKey(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
agentId: string;
|
||||
channel: ChannelId;
|
||||
peer: RoutePeer;
|
||||
@@ -116,7 +116,7 @@ function buildBaseSessionKey(params: {
|
||||
|
||||
// Best-effort mpim detection: allowlist/config, then Slack API (if token available).
|
||||
async function resolveSlackChannelType(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
accountId?: string | null;
|
||||
channelId: string;
|
||||
}): Promise<"channel" | "group" | "dm" | "unknown"> {
|
||||
@@ -805,7 +805,7 @@ export async function resolveOutboundSessionRoute(
|
||||
}
|
||||
|
||||
export async function ensureOutboundSessionEntry(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
agentId: string;
|
||||
channel: ChannelId;
|
||||
accountId?: string | null;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { ChannelDirectoryEntry } from "../../channels/plugins/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import { resetDirectoryCache, resolveMessagingTarget } from "./target-resolver.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
@@ -16,7 +16,7 @@ vi.mock("../../channels/plugins/index.js", () => ({
|
||||
}));
|
||||
|
||||
describe("resolveMessagingTarget (directory fallback)", () => {
|
||||
const cfg = {} as ClawdbotConfig;
|
||||
const cfg = {} as MoltbotConfig;
|
||||
|
||||
beforeEach(() => {
|
||||
mocks.listGroups.mockReset();
|
||||
|
||||
@@ -4,7 +4,7 @@ import type {
|
||||
ChannelDirectoryEntryKind,
|
||||
ChannelId,
|
||||
} from "../../channels/plugins/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import { defaultRuntime, type RuntimeEnv } from "../../runtime.js";
|
||||
import { buildDirectoryCacheKey, DirectoryCache } from "./directory-cache.js";
|
||||
import {
|
||||
@@ -30,7 +30,7 @@ export type ResolveMessagingTargetResult =
|
||||
| { ok: false; error: Error; candidates?: ChannelDirectoryEntry[] };
|
||||
|
||||
export async function resolveChannelTarget(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
input: string;
|
||||
accountId?: string | null;
|
||||
@@ -177,7 +177,7 @@ function resolveMatch(params: {
|
||||
}
|
||||
|
||||
async function listDirectoryEntries(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
accountId?: string | null;
|
||||
kind: ChannelDirectoryEntryKind;
|
||||
@@ -213,7 +213,7 @@ async function listDirectoryEntries(params: {
|
||||
}
|
||||
|
||||
async function getDirectoryEntries(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
accountId?: string | null;
|
||||
kind: ChannelDirectoryEntryKind;
|
||||
@@ -281,7 +281,7 @@ function pickAmbiguousMatch(
|
||||
}
|
||||
|
||||
export async function resolveMessagingTarget(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
input: string;
|
||||
accountId?: string | null;
|
||||
@@ -397,7 +397,7 @@ export async function resolveMessagingTarget(params: {
|
||||
}
|
||||
|
||||
export async function lookupDirectoryDisplay(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
channel: ChannelId;
|
||||
targetId: string;
|
||||
accountId?: string | null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
|
||||
import { setActivePluginRegistry } from "../../plugins/runtime.js";
|
||||
import { createTestRegistry } from "../../test-utils/channel-plugins.js";
|
||||
@@ -18,7 +18,7 @@ describe("resolveOutboundTarget", () => {
|
||||
});
|
||||
|
||||
it("falls back to whatsapp allowFrom via config", () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
const cfg: MoltbotConfig = {
|
||||
channels: { whatsapp: { allowFrom: ["+1555"] } },
|
||||
};
|
||||
const res = resolveOutboundTarget({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { getChannelPlugin, normalizeChannelId } from "../../channels/plugins/index.js";
|
||||
import { formatCliCommand } from "../../cli/command-format.js";
|
||||
import type { ChannelId, ChannelOutboundTargetMode } from "../../channels/plugins/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import type { MoltbotConfig } from "../../config/config.js";
|
||||
import type { SessionEntry } from "../../config/sessions.js";
|
||||
import type { AgentDefaultsConfig } from "../../config/types.agent-defaults.js";
|
||||
import { deliveryContextFromSession } from "../../utils/delivery-context.js";
|
||||
@@ -119,7 +119,7 @@ export function resolveOutboundTarget(params: {
|
||||
channel: GatewayMessageChannel;
|
||||
to?: string;
|
||||
allowFrom?: string[];
|
||||
cfg?: ClawdbotConfig;
|
||||
cfg?: MoltbotConfig;
|
||||
accountId?: string | null;
|
||||
mode?: ChannelOutboundTargetMode;
|
||||
}): OutboundTargetResolution {
|
||||
@@ -127,7 +127,7 @@ export function resolveOutboundTarget(params: {
|
||||
return {
|
||||
ok: false,
|
||||
error: new Error(
|
||||
`Delivering to WebChat is not supported via \`${formatCliCommand("clawdbot agent")}\`; use WhatsApp/Telegram or run with --deliver=false.`,
|
||||
`Delivering to WebChat is not supported via \`${formatCliCommand("moltbot agent")}\`; use WhatsApp/Telegram or run with --deliver=false.`,
|
||||
),
|
||||
};
|
||||
}
|
||||
@@ -172,7 +172,7 @@ export function resolveOutboundTarget(params: {
|
||||
}
|
||||
|
||||
export function resolveHeartbeatDeliveryTarget(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
entry?: SessionEntry;
|
||||
heartbeat?: AgentDefaultsConfig["heartbeat"];
|
||||
}): OutboundTarget {
|
||||
@@ -289,7 +289,7 @@ function resolveHeartbeatSenderId(params: {
|
||||
}
|
||||
|
||||
export function resolveHeartbeatSenderContext(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
entry?: SessionEntry;
|
||||
delivery: OutboundTarget;
|
||||
}): HeartbeatSenderContext {
|
||||
|
||||
@@ -4,15 +4,15 @@ import path from "node:path";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { ensureClawdbotCliOnPath } from "./path-env.js";
|
||||
import { ensureMoltbotCliOnPath } from "./path-env.js";
|
||||
|
||||
describe("ensureClawdbotCliOnPath", () => {
|
||||
it("prepends the bundled app bin dir when a sibling clawdbot exists", async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-path-"));
|
||||
describe("ensureMoltbotCliOnPath", () => {
|
||||
it("prepends the bundled app bin dir when a sibling moltbot exists", async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-path-"));
|
||||
try {
|
||||
const appBinDir = path.join(tmp, "AppBin");
|
||||
await fs.mkdir(appBinDir, { recursive: true });
|
||||
const cliPath = path.join(appBinDir, "clawdbot");
|
||||
const cliPath = path.join(appBinDir, "moltbot");
|
||||
await fs.writeFile(cliPath, "#!/bin/sh\necho ok\n", "utf-8");
|
||||
await fs.chmod(cliPath, 0o755);
|
||||
|
||||
@@ -21,7 +21,7 @@ describe("ensureClawdbotCliOnPath", () => {
|
||||
process.env.PATH = "/usr/bin";
|
||||
delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED;
|
||||
try {
|
||||
ensureClawdbotCliOnPath({
|
||||
ensureMoltbotCliOnPath({
|
||||
execPath: cliPath,
|
||||
cwd: tmp,
|
||||
homeDir: tmp,
|
||||
@@ -45,7 +45,7 @@ describe("ensureClawdbotCliOnPath", () => {
|
||||
process.env.PATH = "/bin";
|
||||
process.env.CLAWDBOT_PATH_BOOTSTRAPPED = "1";
|
||||
try {
|
||||
ensureClawdbotCliOnPath({
|
||||
ensureMoltbotCliOnPath({
|
||||
execPath: "/tmp/does-not-matter",
|
||||
cwd: "/tmp",
|
||||
homeDir: "/tmp",
|
||||
@@ -60,20 +60,20 @@ describe("ensureClawdbotCliOnPath", () => {
|
||||
});
|
||||
|
||||
it("prepends mise shims when available", async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-path-"));
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-path-"));
|
||||
const originalPath = process.env.PATH;
|
||||
const originalFlag = process.env.CLAWDBOT_PATH_BOOTSTRAPPED;
|
||||
const originalMiseDataDir = process.env.MISE_DATA_DIR;
|
||||
try {
|
||||
const appBinDir = path.join(tmp, "AppBin");
|
||||
await fs.mkdir(appBinDir, { recursive: true });
|
||||
const appCli = path.join(appBinDir, "clawdbot");
|
||||
const appCli = path.join(appBinDir, "moltbot");
|
||||
await fs.writeFile(appCli, "#!/bin/sh\necho ok\n", "utf-8");
|
||||
await fs.chmod(appCli, 0o755);
|
||||
|
||||
const localBinDir = path.join(tmp, "node_modules", ".bin");
|
||||
await fs.mkdir(localBinDir, { recursive: true });
|
||||
const localCli = path.join(localBinDir, "clawdbot");
|
||||
const localCli = path.join(localBinDir, "moltbot");
|
||||
await fs.writeFile(localCli, "#!/bin/sh\necho ok\n", "utf-8");
|
||||
await fs.chmod(localCli, 0o755);
|
||||
|
||||
@@ -84,7 +84,7 @@ describe("ensureClawdbotCliOnPath", () => {
|
||||
process.env.PATH = "/usr/bin";
|
||||
delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED;
|
||||
|
||||
ensureClawdbotCliOnPath({
|
||||
ensureMoltbotCliOnPath({
|
||||
execPath: appCli,
|
||||
cwd: tmp,
|
||||
homeDir: tmp,
|
||||
@@ -110,7 +110,7 @@ describe("ensureClawdbotCliOnPath", () => {
|
||||
});
|
||||
|
||||
it("prepends Linuxbrew dirs when present", async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-path-"));
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-path-"));
|
||||
const originalPath = process.env.PATH;
|
||||
const originalFlag = process.env.CLAWDBOT_PATH_BOOTSTRAPPED;
|
||||
const originalHomebrewPrefix = process.env.HOMEBREW_PREFIX;
|
||||
@@ -131,7 +131,7 @@ describe("ensureClawdbotCliOnPath", () => {
|
||||
delete process.env.HOMEBREW_BREW_FILE;
|
||||
delete process.env.XDG_BIN_HOME;
|
||||
|
||||
ensureClawdbotCliOnPath({
|
||||
ensureMoltbotCliOnPath({
|
||||
execPath: path.join(execDir, "node"),
|
||||
cwd: tmp,
|
||||
homeDir: tmp,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { isTruthyEnvValue } from "./env.js";
|
||||
|
||||
import { resolveBrewPathDirs } from "./brew.js";
|
||||
|
||||
type EnsureClawdbotPathOpts = {
|
||||
type EnsureMoltbotPathOpts = {
|
||||
execPath?: string;
|
||||
cwd?: string;
|
||||
homeDir?: string;
|
||||
@@ -48,7 +48,7 @@ function mergePath(params: { existing: string; prepend: string[] }): string {
|
||||
return merged.join(path.delimiter);
|
||||
}
|
||||
|
||||
function candidateBinDirs(opts: EnsureClawdbotPathOpts): string[] {
|
||||
function candidateBinDirs(opts: EnsureMoltbotPathOpts): string[] {
|
||||
const execPath = opts.execPath ?? process.execPath;
|
||||
const cwd = opts.cwd ?? process.cwd();
|
||||
const homeDir = opts.homeDir ?? os.homedir();
|
||||
@@ -56,19 +56,19 @@ function candidateBinDirs(opts: EnsureClawdbotPathOpts): string[] {
|
||||
|
||||
const candidates: string[] = [];
|
||||
|
||||
// Bundled macOS app: `clawdbot` lives next to the executable (process.execPath).
|
||||
// Bundled macOS app: `moltbot` lives next to the executable (process.execPath).
|
||||
try {
|
||||
const execDir = path.dirname(execPath);
|
||||
const siblingClawdbot = path.join(execDir, "clawdbot");
|
||||
if (isExecutable(siblingClawdbot)) candidates.push(execDir);
|
||||
const siblingMoltbot = path.join(execDir, "moltbot");
|
||||
if (isExecutable(siblingMoltbot)) candidates.push(execDir);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// Project-local installs (best effort): if a `node_modules/.bin/clawdbot` exists near cwd,
|
||||
// Project-local installs (best effort): if a `node_modules/.bin/moltbot` exists near cwd,
|
||||
// include it. This helps when running under launchd or other minimal PATH environments.
|
||||
const localBinDir = path.join(cwd, "node_modules", ".bin");
|
||||
if (isExecutable(path.join(localBinDir, "clawdbot"))) candidates.push(localBinDir);
|
||||
if (isExecutable(path.join(localBinDir, "moltbot"))) candidates.push(localBinDir);
|
||||
|
||||
const miseDataDir = process.env.MISE_DATA_DIR ?? path.join(homeDir, ".local", "share", "mise");
|
||||
const miseShims = path.join(miseDataDir, "shims");
|
||||
@@ -91,10 +91,10 @@ function candidateBinDirs(opts: EnsureClawdbotPathOpts): string[] {
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort PATH bootstrap so skills that require the `clawdbot` CLI can run
|
||||
* Best-effort PATH bootstrap so skills that require the `moltbot` CLI can run
|
||||
* under launchd/minimal environments (and inside the macOS app bundle).
|
||||
*/
|
||||
export function ensureClawdbotCliOnPath(opts: EnsureClawdbotPathOpts = {}) {
|
||||
export function ensureMoltbotCliOnPath(opts: EnsureMoltbotPathOpts = {}) {
|
||||
if (isTruthyEnvValue(process.env.CLAWDBOT_PATH_BOOTSTRAPPED)) return;
|
||||
process.env.CLAWDBOT_PATH_BOOTSTRAPPED = "1";
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { PortListener, PortListenerKind, PortUsage } from "./ports-types.js
|
||||
|
||||
export function classifyPortListener(listener: PortListener, port: number): PortListenerKind {
|
||||
const raw = `${listener.commandLine ?? ""} ${listener.command ?? ""}`.trim().toLowerCase();
|
||||
if (raw.includes("clawdbot")) return "gateway";
|
||||
if (raw.includes("moltbot")) return "gateway";
|
||||
if (raw.includes("ssh")) {
|
||||
const portToken = String(port);
|
||||
const tunnelPattern = new RegExp(
|
||||
@@ -21,7 +21,7 @@ export function buildPortHints(listeners: PortListener[], port: number): string[
|
||||
const hints: string[] = [];
|
||||
if (kinds.has("gateway")) {
|
||||
hints.push(
|
||||
`Gateway already running locally. Stop it (${formatCliCommand("clawdbot gateway stop")}) or use a different port.`,
|
||||
`Gateway already running locally. Stop it (${formatCliCommand("moltbot gateway stop")}) or use a different port.`,
|
||||
);
|
||||
}
|
||||
if (kinds.has("ssh")) {
|
||||
|
||||
@@ -37,7 +37,7 @@ describe("ports helpers", () => {
|
||||
expect(
|
||||
classifyPortListener(
|
||||
{
|
||||
commandLine: "node /Users/me/Projects/clawdbot/dist/entry.js gateway",
|
||||
commandLine: "node /Users/me/Projects/moltbot/dist/entry.js gateway",
|
||||
},
|
||||
18789,
|
||||
),
|
||||
|
||||
@@ -63,10 +63,10 @@ export async function handlePortError(
|
||||
if (details) {
|
||||
runtime.error(info("Port listener details:"));
|
||||
runtime.error(details);
|
||||
if (/clawdbot|src\/index\.ts|dist\/index\.js/.test(details)) {
|
||||
if (/moltbot|src\/index\.ts|dist\/index\.js/.test(details)) {
|
||||
runtime.error(
|
||||
warn(
|
||||
"It looks like another clawdbot instance is already running. Stop it or pick a different port.",
|
||||
"It looks like another moltbot instance is already running. Stop it or pick a different port.",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ export async function fetchClaudeUsage(
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
"User-Agent": "clawdbot",
|
||||
"User-Agent": "moltbot",
|
||||
Accept: "application/json",
|
||||
"anthropic-version": "2023-06-01",
|
||||
"anthropic-beta": "oauth-2025-04-20",
|
||||
|
||||
@@ -289,7 +289,7 @@ export async function fetchMinimaxUsage(
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
"MM-API-Source": "Clawdbot",
|
||||
"MM-API-Source": "Moltbot",
|
||||
},
|
||||
},
|
||||
timeoutMs,
|
||||
|
||||
@@ -330,7 +330,7 @@ describe("provider usage loading", () => {
|
||||
env: {
|
||||
CLAWDBOT_STATE_DIR: (home) => path.join(home, ".clawdbot"),
|
||||
},
|
||||
prefix: "clawdbot-provider-usage-",
|
||||
prefix: "moltbot-provider-usage-",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@ describe("restart sentinel", () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
prevStateDir = process.env.CLAWDBOT_STATE_DIR;
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-sentinel-"));
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-sentinel-"));
|
||||
process.env.CLAWDBOT_STATE_DIR = tempDir;
|
||||
});
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ const SENTINEL_FILENAME = "restart-sentinel.json";
|
||||
export function formatDoctorNonInteractiveHint(
|
||||
env: Record<string, string | undefined> = process.env as Record<string, string | undefined>,
|
||||
): string {
|
||||
return `Run: ${formatCliCommand("clawdbot doctor --non-interactive", env)}`;
|
||||
return `Run: ${formatCliCommand("moltbot doctor --non-interactive", env)}`;
|
||||
}
|
||||
|
||||
export function resolveRestartSentinelPath(env: NodeJS.ProcessEnv = process.env): string {
|
||||
|
||||
@@ -87,7 +87,7 @@ function normalizeSystemdUnit(raw?: string, profile?: string): string {
|
||||
return unit.endsWith(".service") ? unit : `${unit}.service`;
|
||||
}
|
||||
|
||||
export function triggerClawdbotRestart(): RestartAttempt {
|
||||
export function triggerMoltbotRestart(): RestartAttempt {
|
||||
if (process.env.VITEST || process.env.NODE_ENV === "test") {
|
||||
return { ok: true, method: "supervisor", detail: "test mode" };
|
||||
}
|
||||
|
||||
@@ -75,11 +75,11 @@ export function assertSupportedRuntime(
|
||||
|
||||
runtime.error(
|
||||
[
|
||||
"clawdbot requires Node >=22.0.0.",
|
||||
"moltbot requires Node >=22.0.0.",
|
||||
`Detected: ${runtimeLabel} (exec: ${execLabel}).`,
|
||||
`PATH searched: ${details.pathEnv}`,
|
||||
"Install Node: https://nodejs.org/en/download",
|
||||
"Upgrade Node and re-run clawdbot.",
|
||||
"Upgrade Node and re-run moltbot.",
|
||||
].join("\n"),
|
||||
);
|
||||
runtime.exit(1);
|
||||
|
||||
@@ -4,12 +4,12 @@ import path from "node:path";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import { loadCostUsageSummary, loadSessionCostSummary } from "./session-cost-usage.js";
|
||||
|
||||
describe("session cost usage", () => {
|
||||
it("aggregates daily totals with log cost and pricing fallback", async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-cost-"));
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-cost-"));
|
||||
const sessionsDir = path.join(root, "agents", "main", "sessions");
|
||||
await fs.mkdir(sessionsDir, { recursive: true });
|
||||
const sessionFile = path.join(sessionsDir, "sess-1.jsonl");
|
||||
@@ -92,7 +92,7 @@ describe("session cost usage", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
} as MoltbotConfig;
|
||||
|
||||
const originalState = process.env.CLAWDBOT_STATE_DIR;
|
||||
process.env.CLAWDBOT_STATE_DIR = root;
|
||||
@@ -108,7 +108,7 @@ describe("session cost usage", () => {
|
||||
});
|
||||
|
||||
it("summarizes a single session file", async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-cost-session-"));
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-cost-session-"));
|
||||
const sessionFile = path.join(root, "session.jsonl");
|
||||
const now = new Date();
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import readline from "node:readline";
|
||||
|
||||
import type { NormalizedUsage, UsageLike } from "../agents/usage.js";
|
||||
import { normalizeUsage } from "../agents/usage.js";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import type { SessionEntry } from "../config/sessions/types.js";
|
||||
import {
|
||||
resolveSessionFilePath,
|
||||
@@ -138,7 +138,7 @@ const applyCostTotal = (totals: CostUsageTotals, costTotal: number | undefined)
|
||||
|
||||
async function scanUsageFile(params: {
|
||||
filePath: string;
|
||||
config?: ClawdbotConfig;
|
||||
config?: MoltbotConfig;
|
||||
onEntry: (entry: ParsedUsageEntry) => void;
|
||||
}): Promise<void> {
|
||||
const fileStream = fs.createReadStream(params.filePath, { encoding: "utf-8" });
|
||||
@@ -170,7 +170,7 @@ async function scanUsageFile(params: {
|
||||
|
||||
export async function loadCostUsageSummary(params?: {
|
||||
days?: number;
|
||||
config?: ClawdbotConfig;
|
||||
config?: MoltbotConfig;
|
||||
agentId?: string;
|
||||
}): Promise<CostUsageSummary> {
|
||||
const days = Math.max(1, Math.floor(params?.days ?? 30));
|
||||
@@ -233,7 +233,7 @@ export async function loadSessionCostSummary(params: {
|
||||
sessionId?: string;
|
||||
sessionEntry?: SessionEntry;
|
||||
sessionFile?: string;
|
||||
config?: ClawdbotConfig;
|
||||
config?: MoltbotConfig;
|
||||
}): Promise<SessionCostSummary | null> {
|
||||
const sessionFile =
|
||||
params.sessionFile ??
|
||||
|
||||
@@ -74,7 +74,7 @@ export function loadShellEnvFallback(opts: ShellEnvFallbackOptions): ShellEnvFal
|
||||
});
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
logger.warn(`[clawdbot] shell env fallback failed: ${msg}`);
|
||||
logger.warn(`[moltbot] shell env fallback failed: ${msg}`);
|
||||
lastAppliedKeys = [];
|
||||
return { ok: false, error: msg, applied: [] };
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { SkillEligibilityContext, SkillEntry } from "../agents/skills.js";
|
||||
import { loadWorkspaceSkillEntries } from "../agents/skills.js";
|
||||
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import { listNodePairing, updatePairedNodeMetadata } from "./node-pairing.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { bumpSkillsSnapshotVersion } from "../agents/skills/refresh.js";
|
||||
@@ -156,7 +156,7 @@ export function recordRemoteNodeBins(nodeId: string, bins: string[]) {
|
||||
upsertNode({ nodeId, bins });
|
||||
}
|
||||
|
||||
function listWorkspaceDirs(cfg: ClawdbotConfig): string[] {
|
||||
function listWorkspaceDirs(cfg: MoltbotConfig): string[] {
|
||||
const dirs = new Set<string>();
|
||||
const list = cfg.agents?.list;
|
||||
if (Array.isArray(list)) {
|
||||
@@ -173,10 +173,10 @@ function listWorkspaceDirs(cfg: ClawdbotConfig): string[] {
|
||||
function collectRequiredBins(entries: SkillEntry[], targetPlatform: string): string[] {
|
||||
const bins = new Set<string>();
|
||||
for (const entry of entries) {
|
||||
const os = entry.clawdbot?.os ?? [];
|
||||
const os = entry.metadata?.os ?? [];
|
||||
if (os.length > 0 && !os.includes(targetPlatform)) continue;
|
||||
const required = entry.clawdbot?.requires?.bins ?? [];
|
||||
const anyBins = entry.clawdbot?.requires?.anyBins ?? [];
|
||||
const required = entry.metadata?.requires?.bins ?? [];
|
||||
const anyBins = entry.metadata?.requires?.anyBins ?? [];
|
||||
for (const bin of required) {
|
||||
if (bin.trim()) bins.add(bin.trim());
|
||||
}
|
||||
@@ -227,7 +227,7 @@ export async function refreshRemoteNodeBins(params: {
|
||||
platform?: string;
|
||||
deviceFamily?: string;
|
||||
commands?: string[];
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
timeoutMs?: number;
|
||||
}) {
|
||||
if (!remoteRegistry) return;
|
||||
@@ -304,7 +304,7 @@ export function getRemoteSkillEligibility(): SkillEligibilityContext["remote"] |
|
||||
};
|
||||
}
|
||||
|
||||
export async function refreshRemoteBinsForConnectedNodes(cfg: ClawdbotConfig) {
|
||||
export async function refreshRemoteBinsForConnectedNodes(cfg: MoltbotConfig) {
|
||||
if (!remoteRegistry) return;
|
||||
const connected = remoteRegistry.listConnected();
|
||||
for (const node of connected) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { readSessionStoreJson5 } from "./state-migrations.fs.js";
|
||||
|
||||
describe("state migrations fs", () => {
|
||||
it("treats array session stores as invalid", async () => {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-session-store-"));
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-store-"));
|
||||
const storePath = path.join(dir, "sessions.json");
|
||||
await fs.writeFile(storePath, "[]", "utf-8");
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import { resolveOAuthDir, resolveStateDir } from "../config/paths.js";
|
||||
import type { SessionEntry } from "../config/sessions.js";
|
||||
import type { SessionScope } from "../config/sessions/types.js";
|
||||
@@ -268,7 +268,7 @@ export function resetAutoMigrateLegacyAgentDirForTest() {
|
||||
}
|
||||
|
||||
export async function detectLegacyStateMigrations(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
homedir?: () => string;
|
||||
}): Promise<LegacyStateDetection> {
|
||||
@@ -559,7 +559,7 @@ export async function runLegacyStateMigrations(params: {
|
||||
}
|
||||
|
||||
export async function autoMigrateLegacyAgentDir(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
homedir?: () => string;
|
||||
log?: MigrationLogger;
|
||||
@@ -574,7 +574,7 @@ export async function autoMigrateLegacyAgentDir(params: {
|
||||
}
|
||||
|
||||
export async function autoMigrateLegacyState(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
cfg: MoltbotConfig;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
homedir?: () => string;
|
||||
log?: MigrationLogger;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
import { prependSystemEvents } from "../auto-reply/reply/session-updates.js";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
import { resolveMainSessionKey } from "../config/sessions.js";
|
||||
import { enqueueSystemEvent, peekSystemEvents, resetSystemEventsForTest } from "./system-events.js";
|
||||
|
||||
const cfg = {} as unknown as ClawdbotConfig;
|
||||
const cfg = {} as unknown as MoltbotConfig;
|
||||
const mainKey = resolveMainSessionKey(cfg);
|
||||
|
||||
describe("system events (session routing)", () => {
|
||||
|
||||
@@ -8,7 +8,7 @@ describe("system-presence", () => {
|
||||
const instanceIdLower = instanceIdUpper.toLowerCase();
|
||||
|
||||
upsertPresence(instanceIdUpper, {
|
||||
host: "clawdbot",
|
||||
host: "moltbot",
|
||||
mode: "ui",
|
||||
instanceId: instanceIdUpper,
|
||||
reason: "connect",
|
||||
@@ -39,7 +39,7 @@ describe("system-presence", () => {
|
||||
|
||||
upsertPresence(deviceId, {
|
||||
deviceId,
|
||||
host: "clawdbot",
|
||||
host: "moltbot",
|
||||
roles: ["operator"],
|
||||
scopes: ["operator.admin"],
|
||||
reason: "connect",
|
||||
|
||||
@@ -345,7 +345,7 @@ export async function ensureFunnel(
|
||||
runtime.error("Failed to enable Tailscale Funnel. Is it allowed on your tailnet?");
|
||||
runtime.error(
|
||||
info(
|
||||
`Tip: Funnel is optional for CLAWDBOT. You can keep running the web gateway without it: \`${formatCliCommand("clawdbot gateway")}\``,
|
||||
`Tip: Funnel is optional for Moltbot. You can keep running the web gateway without it: \`${formatCliCommand("moltbot gateway")}\``,
|
||||
),
|
||||
);
|
||||
if (shouldLogVerbose()) {
|
||||
|
||||
@@ -56,7 +56,7 @@ async function generateSelfSignedCert(params: {
|
||||
"-out",
|
||||
params.certPath,
|
||||
"-subj",
|
||||
"/CN=clawdbot-gateway",
|
||||
"/CN=moltbot-gateway",
|
||||
]);
|
||||
await fs.chmod(params.keyPath, 0o600).catch(() => {});
|
||||
await fs.chmod(params.certPath, 0o600).catch(() => {});
|
||||
|
||||
@@ -96,7 +96,7 @@ export function isUnhandledRejectionHandled(reason: unknown): boolean {
|
||||
if (handler(reason)) return true;
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"[clawdbot] Unhandled rejection handler failed:",
|
||||
"[moltbot] Unhandled rejection handler failed:",
|
||||
err instanceof Error ? (err.stack ?? err.message) : err,
|
||||
);
|
||||
}
|
||||
@@ -111,18 +111,18 @@ export function installUnhandledRejectionHandler(): void {
|
||||
// AbortError is typically an intentional cancellation (e.g., during shutdown)
|
||||
// Log it but don't crash - these are expected during graceful shutdown
|
||||
if (isAbortError(reason)) {
|
||||
console.warn("[clawdbot] Suppressed AbortError:", formatUncaughtError(reason));
|
||||
console.warn("[moltbot] Suppressed AbortError:", formatUncaughtError(reason));
|
||||
return;
|
||||
}
|
||||
|
||||
// Transient network errors (fetch failed, connection reset, etc.) shouldn't crash
|
||||
// These are temporary connectivity issues that will resolve on their own
|
||||
if (isTransientNetworkError(reason)) {
|
||||
console.error("[clawdbot] Network error (non-fatal):", formatUncaughtError(reason));
|
||||
console.error("[moltbot] Network error (non-fatal):", formatUncaughtError(reason));
|
||||
return;
|
||||
}
|
||||
|
||||
console.error("[clawdbot] Unhandled promise rejection:", formatUncaughtError(reason));
|
||||
console.error("[moltbot] Unhandled promise rejection:", formatUncaughtError(reason));
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ export async function fetchNpmTagVersion(params: {
|
||||
const tag = params.tag;
|
||||
try {
|
||||
const res = await fetchWithTimeout(
|
||||
`https://registry.npmjs.org/clawdbot/${encodeURIComponent(tag)}`,
|
||||
`https://registry.npmjs.org/moltbot/${encodeURIComponent(tag)}`,
|
||||
timeoutMs,
|
||||
);
|
||||
if (!res.ok) {
|
||||
|
||||
@@ -51,7 +51,7 @@ export async function resolveGlobalPackageRoot(
|
||||
): Promise<string | null> {
|
||||
const root = await resolveGlobalRoot(manager, runCommand, timeoutMs);
|
||||
if (!root) return null;
|
||||
return path.join(root, "clawdbot");
|
||||
return path.join(root, "moltbot");
|
||||
}
|
||||
|
||||
export async function detectGlobalInstallManagerForRoot(
|
||||
@@ -75,13 +75,13 @@ export async function detectGlobalInstallManagerForRoot(
|
||||
const globalRoot = res.stdout.trim();
|
||||
if (!globalRoot) continue;
|
||||
const globalReal = await tryRealpath(globalRoot);
|
||||
const expected = path.join(globalReal, "clawdbot");
|
||||
const expected = path.join(globalReal, "moltbot");
|
||||
if (path.resolve(expected) === path.resolve(pkgReal)) return manager;
|
||||
}
|
||||
|
||||
const bunGlobalRoot = resolveBunGlobalRoot();
|
||||
const bunGlobalReal = await tryRealpath(bunGlobalRoot);
|
||||
const bunExpected = path.join(bunGlobalReal, "clawdbot");
|
||||
const bunExpected = path.join(bunGlobalReal, "moltbot");
|
||||
if (path.resolve(bunExpected) === path.resolve(pkgReal)) return "bun";
|
||||
|
||||
return null;
|
||||
@@ -94,11 +94,11 @@ export async function detectGlobalInstallManagerByPresence(
|
||||
for (const manager of ["npm", "pnpm"] as const) {
|
||||
const root = await resolveGlobalRoot(manager, runCommand, timeoutMs);
|
||||
if (!root) continue;
|
||||
if (await pathExists(path.join(root, "clawdbot"))) return manager;
|
||||
if (await pathExists(path.join(root, "moltbot"))) return manager;
|
||||
}
|
||||
|
||||
const bunRoot = resolveBunGlobalRoot();
|
||||
if (await pathExists(path.join(bunRoot, "clawdbot"))) return "bun";
|
||||
if (await pathExists(path.join(bunRoot, "moltbot"))) return "bun";
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ describe("runGatewayUpdate", () => {
|
||||
let tempDir: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-update-"));
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-update-"));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -37,7 +37,7 @@ describe("runGatewayUpdate", () => {
|
||||
await fs.mkdir(path.join(tempDir, ".git"));
|
||||
await fs.writeFile(
|
||||
path.join(tempDir, "package.json"),
|
||||
JSON.stringify({ name: "clawdbot", version: "1.0.0" }),
|
||||
JSON.stringify({ name: "moltbot", version: "1.0.0" }),
|
||||
"utf-8",
|
||||
);
|
||||
const { runner, calls } = createRunner({
|
||||
@@ -62,7 +62,7 @@ describe("runGatewayUpdate", () => {
|
||||
await fs.mkdir(path.join(tempDir, ".git"));
|
||||
await fs.writeFile(
|
||||
path.join(tempDir, "package.json"),
|
||||
JSON.stringify({ name: "clawdbot", version: "1.0.0" }),
|
||||
JSON.stringify({ name: "moltbot", version: "1.0.0" }),
|
||||
"utf-8",
|
||||
);
|
||||
const { runner, calls } = createRunner({
|
||||
@@ -95,7 +95,7 @@ describe("runGatewayUpdate", () => {
|
||||
await fs.mkdir(path.join(tempDir, ".git"));
|
||||
await fs.writeFile(
|
||||
path.join(tempDir, "package.json"),
|
||||
JSON.stringify({ name: "clawdbot", version: "1.0.0", packageManager: "pnpm@8.0.0" }),
|
||||
JSON.stringify({ name: "moltbot", version: "1.0.0", packageManager: "pnpm@8.0.0" }),
|
||||
"utf-8",
|
||||
);
|
||||
const stableTag = "v1.0.1-1";
|
||||
@@ -113,7 +113,7 @@ describe("runGatewayUpdate", () => {
|
||||
"pnpm build": { stdout: "" },
|
||||
"pnpm ui:build": { stdout: "" },
|
||||
[`git -C ${tempDir} checkout -- dist/control-ui/`]: { stdout: "" },
|
||||
"pnpm clawdbot doctor --non-interactive": { stdout: "" },
|
||||
"pnpm moltbot doctor --non-interactive": { stdout: "" },
|
||||
});
|
||||
|
||||
const result = await runGatewayUpdate({
|
||||
@@ -131,7 +131,7 @@ describe("runGatewayUpdate", () => {
|
||||
it("skips update when no git root", async () => {
|
||||
await fs.writeFile(
|
||||
path.join(tempDir, "package.json"),
|
||||
JSON.stringify({ name: "clawdbot", packageManager: "pnpm@8.0.0" }),
|
||||
JSON.stringify({ name: "moltbot", packageManager: "pnpm@8.0.0" }),
|
||||
"utf-8",
|
||||
);
|
||||
await fs.writeFile(path.join(tempDir, "pnpm-lock.yaml"), "", "utf-8");
|
||||
@@ -155,11 +155,11 @@ describe("runGatewayUpdate", () => {
|
||||
|
||||
it("updates global npm installs when detected", async () => {
|
||||
const nodeModules = path.join(tempDir, "node_modules");
|
||||
const pkgRoot = path.join(nodeModules, "clawdbot");
|
||||
const pkgRoot = path.join(nodeModules, "moltbot");
|
||||
await fs.mkdir(pkgRoot, { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(pkgRoot, "package.json"),
|
||||
JSON.stringify({ name: "clawdbot", version: "1.0.0" }),
|
||||
JSON.stringify({ name: "moltbot", version: "1.0.0" }),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
@@ -173,10 +173,10 @@ describe("runGatewayUpdate", () => {
|
||||
if (key === "npm root -g") {
|
||||
return { stdout: nodeModules, stderr: "", code: 0 };
|
||||
}
|
||||
if (key === "npm i -g clawdbot@latest") {
|
||||
if (key === "npm i -g moltbot@latest") {
|
||||
await fs.writeFile(
|
||||
path.join(pkgRoot, "package.json"),
|
||||
JSON.stringify({ name: "clawdbot", version: "2.0.0" }),
|
||||
JSON.stringify({ name: "moltbot", version: "2.0.0" }),
|
||||
"utf-8",
|
||||
);
|
||||
return { stdout: "ok", stderr: "", code: 0 };
|
||||
@@ -197,16 +197,16 @@ describe("runGatewayUpdate", () => {
|
||||
expect(result.mode).toBe("npm");
|
||||
expect(result.before?.version).toBe("1.0.0");
|
||||
expect(result.after?.version).toBe("2.0.0");
|
||||
expect(calls.some((call) => call === "npm i -g clawdbot@latest")).toBe(true);
|
||||
expect(calls.some((call) => call === "npm i -g moltbot@latest")).toBe(true);
|
||||
});
|
||||
|
||||
it("updates global npm installs with tag override", async () => {
|
||||
const nodeModules = path.join(tempDir, "node_modules");
|
||||
const pkgRoot = path.join(nodeModules, "clawdbot");
|
||||
const pkgRoot = path.join(nodeModules, "moltbot");
|
||||
await fs.mkdir(pkgRoot, { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(pkgRoot, "package.json"),
|
||||
JSON.stringify({ name: "clawdbot", version: "1.0.0" }),
|
||||
JSON.stringify({ name: "moltbot", version: "1.0.0" }),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
@@ -220,10 +220,10 @@ describe("runGatewayUpdate", () => {
|
||||
if (key === "npm root -g") {
|
||||
return { stdout: nodeModules, stderr: "", code: 0 };
|
||||
}
|
||||
if (key === "npm i -g clawdbot@beta") {
|
||||
if (key === "npm i -g moltbot@beta") {
|
||||
await fs.writeFile(
|
||||
path.join(pkgRoot, "package.json"),
|
||||
JSON.stringify({ name: "clawdbot", version: "2.0.0" }),
|
||||
JSON.stringify({ name: "moltbot", version: "2.0.0" }),
|
||||
"utf-8",
|
||||
);
|
||||
return { stdout: "ok", stderr: "", code: 0 };
|
||||
@@ -245,7 +245,7 @@ describe("runGatewayUpdate", () => {
|
||||
expect(result.mode).toBe("npm");
|
||||
expect(result.before?.version).toBe("1.0.0");
|
||||
expect(result.after?.version).toBe("2.0.0");
|
||||
expect(calls.some((call) => call === "npm i -g clawdbot@beta")).toBe(true);
|
||||
expect(calls.some((call) => call === "npm i -g moltbot@beta")).toBe(true);
|
||||
});
|
||||
|
||||
it("updates global bun installs when detected", async () => {
|
||||
@@ -255,11 +255,11 @@ describe("runGatewayUpdate", () => {
|
||||
|
||||
try {
|
||||
const bunGlobalRoot = path.join(bunInstall, "install", "global", "node_modules");
|
||||
const pkgRoot = path.join(bunGlobalRoot, "clawdbot");
|
||||
const pkgRoot = path.join(bunGlobalRoot, "moltbot");
|
||||
await fs.mkdir(pkgRoot, { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(pkgRoot, "package.json"),
|
||||
JSON.stringify({ name: "clawdbot", version: "1.0.0" }),
|
||||
JSON.stringify({ name: "moltbot", version: "1.0.0" }),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
@@ -276,10 +276,10 @@ describe("runGatewayUpdate", () => {
|
||||
if (key === "pnpm root -g") {
|
||||
return { stdout: "", stderr: "", code: 1 };
|
||||
}
|
||||
if (key === "bun add -g clawdbot@latest") {
|
||||
if (key === "bun add -g moltbot@latest") {
|
||||
await fs.writeFile(
|
||||
path.join(pkgRoot, "package.json"),
|
||||
JSON.stringify({ name: "clawdbot", version: "2.0.0" }),
|
||||
JSON.stringify({ name: "moltbot", version: "2.0.0" }),
|
||||
"utf-8",
|
||||
);
|
||||
return { stdout: "ok", stderr: "", code: 0 };
|
||||
@@ -297,14 +297,14 @@ describe("runGatewayUpdate", () => {
|
||||
expect(result.mode).toBe("bun");
|
||||
expect(result.before?.version).toBe("1.0.0");
|
||||
expect(result.after?.version).toBe("2.0.0");
|
||||
expect(calls.some((call) => call === "bun add -g clawdbot@latest")).toBe(true);
|
||||
expect(calls.some((call) => call === "bun add -g moltbot@latest")).toBe(true);
|
||||
} finally {
|
||||
if (oldBunInstall === undefined) delete process.env.BUN_INSTALL;
|
||||
else process.env.BUN_INSTALL = oldBunInstall;
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects git roots that are not a clawdbot checkout", async () => {
|
||||
it("rejects git roots that are not a moltbot checkout", async () => {
|
||||
await fs.mkdir(path.join(tempDir, ".git"));
|
||||
const cwdSpy = vi.spyOn(process, "cwd").mockReturnValue(tempDir);
|
||||
const { runner, calls } = createRunner({
|
||||
@@ -320,7 +320,7 @@ describe("runGatewayUpdate", () => {
|
||||
cwdSpy.mockRestore();
|
||||
|
||||
expect(result.status).toBe("error");
|
||||
expect(result.reason).toBe("not-clawdbot-root");
|
||||
expect(result.reason).toBe("not-moltbot-root");
|
||||
expect(calls.some((call) => call.includes("status --porcelain"))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -67,7 +67,7 @@ const MAX_LOG_CHARS = 8000;
|
||||
const PREFLIGHT_MAX_COMMITS = 10;
|
||||
const START_DIRS = ["cwd", "argv1", "process"];
|
||||
const DEFAULT_PACKAGE_NAME = "moltbot";
|
||||
const CORE_PACKAGE_NAMES = new Set([DEFAULT_PACKAGE_NAME, "clawdbot"]);
|
||||
const CORE_PACKAGE_NAMES = new Set([DEFAULT_PACKAGE_NAME, "moltbot"]);
|
||||
|
||||
function normalizeDir(value?: string | null) {
|
||||
if (!value) return null;
|
||||
@@ -291,7 +291,7 @@ function managerInstallArgs(manager: "pnpm" | "bun" | "npm") {
|
||||
function normalizeTag(tag?: string) {
|
||||
const trimmed = tag?.trim();
|
||||
if (!trimmed) return "latest";
|
||||
if (trimmed.startsWith("clawdbot@")) return trimmed.slice("clawdbot@".length);
|
||||
if (trimmed.startsWith("moltbot@")) return trimmed.slice("moltbot@".length);
|
||||
if (trimmed.startsWith(`${DEFAULT_PACKAGE_NAME}@`)) {
|
||||
return trimmed.slice(`${DEFAULT_PACKAGE_NAME}@`.length);
|
||||
}
|
||||
@@ -347,7 +347,7 @@ export async function runGatewayUpdate(opts: UpdateRunnerOptions = {}): Promise<
|
||||
status: "error",
|
||||
mode: "unknown",
|
||||
root: gitRoot,
|
||||
reason: "not-clawdbot-root",
|
||||
reason: "not-moltbot-root",
|
||||
steps: [],
|
||||
durationMs: Date.now() - startedAt,
|
||||
};
|
||||
@@ -502,7 +502,7 @@ export async function runGatewayUpdate(opts: UpdateRunnerOptions = {}): Promise<
|
||||
}
|
||||
|
||||
const manager = await detectPackageManager(gitRoot);
|
||||
const preflightRoot = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-update-preflight-"));
|
||||
const preflightRoot = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-update-preflight-"));
|
||||
const worktreeDir = path.join(preflightRoot, "worktree");
|
||||
const worktreeStep = await runStep(
|
||||
step(
|
||||
@@ -689,8 +689,8 @@ export async function runGatewayUpdate(opts: UpdateRunnerOptions = {}): Promise<
|
||||
|
||||
const doctorStep = await runStep(
|
||||
step(
|
||||
"clawdbot doctor",
|
||||
managerScriptArgs(manager, "clawdbot", ["doctor", "--non-interactive"]),
|
||||
"moltbot doctor",
|
||||
managerScriptArgs(manager, "moltbot", ["doctor", "--non-interactive"]),
|
||||
gitRoot,
|
||||
{ CLAWDBOT_UPDATE_IN_PROGRESS: "1" },
|
||||
),
|
||||
|
||||
@@ -5,8 +5,8 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { UpdateCheckResult } from "./update-check.js";
|
||||
|
||||
vi.mock("./clawdbot-root.js", () => ({
|
||||
resolveClawdbotPackageRoot: vi.fn(),
|
||||
vi.mock("./moltbot-root.js", () => ({
|
||||
resolveMoltbotPackageRoot: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("./update-check.js", async () => {
|
||||
@@ -30,7 +30,7 @@ describe("update-startup", () => {
|
||||
beforeEach(async () => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date("2026-01-17T10:00:00Z"));
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-update-check-"));
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-update-check-"));
|
||||
process.env.CLAWDBOT_STATE_DIR = tempDir;
|
||||
delete process.env.VITEST;
|
||||
process.env.NODE_ENV = "test";
|
||||
@@ -43,13 +43,13 @@ describe("update-startup", () => {
|
||||
});
|
||||
|
||||
it("logs update hint for npm installs when newer tag exists", async () => {
|
||||
const { resolveClawdbotPackageRoot } = await import("./clawdbot-root.js");
|
||||
const { resolveMoltbotPackageRoot } = await import("./moltbot-root.js");
|
||||
const { checkUpdateStatus, resolveNpmChannelTag } = await import("./update-check.js");
|
||||
const { runGatewayUpdateCheck } = await import("./update-startup.js");
|
||||
|
||||
vi.mocked(resolveClawdbotPackageRoot).mockResolvedValue("/opt/clawdbot");
|
||||
vi.mocked(resolveMoltbotPackageRoot).mockResolvedValue("/opt/moltbot");
|
||||
vi.mocked(checkUpdateStatus).mockResolvedValue({
|
||||
root: "/opt/clawdbot",
|
||||
root: "/opt/moltbot",
|
||||
installKind: "package",
|
||||
packageManager: "npm",
|
||||
} satisfies UpdateCheckResult);
|
||||
@@ -77,13 +77,13 @@ describe("update-startup", () => {
|
||||
});
|
||||
|
||||
it("uses latest when beta tag is older than release", async () => {
|
||||
const { resolveClawdbotPackageRoot } = await import("./clawdbot-root.js");
|
||||
const { resolveMoltbotPackageRoot } = await import("./moltbot-root.js");
|
||||
const { checkUpdateStatus, resolveNpmChannelTag } = await import("./update-check.js");
|
||||
const { runGatewayUpdateCheck } = await import("./update-startup.js");
|
||||
|
||||
vi.mocked(resolveClawdbotPackageRoot).mockResolvedValue("/opt/clawdbot");
|
||||
vi.mocked(resolveMoltbotPackageRoot).mockResolvedValue("/opt/moltbot");
|
||||
vi.mocked(checkUpdateStatus).mockResolvedValue({
|
||||
root: "/opt/clawdbot",
|
||||
root: "/opt/moltbot",
|
||||
installKind: "package",
|
||||
packageManager: "npm",
|
||||
} satisfies UpdateCheckResult);
|
||||
|
||||
@@ -3,7 +3,7 @@ import path from "node:path";
|
||||
|
||||
import type { loadConfig } from "../config/config.js";
|
||||
import { resolveStateDir } from "../config/paths.js";
|
||||
import { resolveClawdbotPackageRoot } from "./clawdbot-root.js";
|
||||
import { resolveMoltbotPackageRoot } from "./moltbot-root.js";
|
||||
import { compareSemverStrings, resolveNpmChannelTag, checkUpdateStatus } from "./update-check.js";
|
||||
import { normalizeUpdateChannel, DEFAULT_PACKAGE_CHANNEL } from "./update-channels.js";
|
||||
import { VERSION } from "../version.js";
|
||||
@@ -57,7 +57,7 @@ export async function runGatewayUpdateCheck(params: {
|
||||
if (now - lastCheckedAt < UPDATE_CHECK_INTERVAL_MS) return;
|
||||
}
|
||||
|
||||
const root = await resolveClawdbotPackageRoot({
|
||||
const root = await resolveMoltbotPackageRoot({
|
||||
moduleUrl: import.meta.url,
|
||||
argv1: process.argv[1],
|
||||
cwd: process.cwd(),
|
||||
@@ -93,7 +93,7 @@ export async function runGatewayUpdateCheck(params: {
|
||||
state.lastNotifiedVersion !== resolved.version || state.lastNotifiedTag !== tag;
|
||||
if (shouldNotify) {
|
||||
params.log.info(
|
||||
`update available (${tag}): v${resolved.version} (current v${VERSION}). Run: ${formatCliCommand("clawdbot update")}`,
|
||||
`update available (${tag}): v${resolved.version} (current v${VERSION}). Run: ${formatCliCommand("moltbot update")}`,
|
||||
);
|
||||
nextState.lastNotifiedVersion = resolved.version;
|
||||
nextState.lastNotifiedTag = tag;
|
||||
|
||||
@@ -12,14 +12,14 @@ import {
|
||||
|
||||
describe("voicewake store", () => {
|
||||
it("returns defaults when missing", async () => {
|
||||
const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-voicewake-"));
|
||||
const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-voicewake-"));
|
||||
const cfg = await loadVoiceWakeConfig(baseDir);
|
||||
expect(cfg.triggers).toEqual(defaultVoiceWakeTriggers());
|
||||
expect(cfg.updatedAtMs).toBe(0);
|
||||
});
|
||||
|
||||
it("sanitizes and persists triggers", async () => {
|
||||
const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-voicewake-"));
|
||||
const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-voicewake-"));
|
||||
const saved = await setVoiceWakeTriggers([" hi ", "", " there "], baseDir);
|
||||
expect(saved.triggers).toEqual(["hi", "there"]);
|
||||
expect(saved.updatedAtMs).toBeGreaterThan(0);
|
||||
@@ -30,7 +30,7 @@ describe("voicewake store", () => {
|
||||
});
|
||||
|
||||
it("falls back to defaults when triggers empty", async () => {
|
||||
const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-voicewake-"));
|
||||
const baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-voicewake-"));
|
||||
const saved = await setVoiceWakeTriggers(["", " "], baseDir);
|
||||
expect(saved.triggers).toEqual(defaultVoiceWakeTriggers());
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const warningFilterKey = Symbol.for("clawdbot.warning-filter");
|
||||
const warningFilterKey = Symbol.for("moltbot.warning-filter");
|
||||
|
||||
type Warning = Error & {
|
||||
code?: string;
|
||||
|
||||
@@ -3,35 +3,35 @@ import { describe, expect, it } from "vitest";
|
||||
import { renderWideAreaGatewayZoneText, WIDE_AREA_DISCOVERY_DOMAIN } from "./widearea-dns.js";
|
||||
|
||||
describe("wide-area DNS-SD zone rendering", () => {
|
||||
it("renders a clawdbot.internal zone with gateway PTR/SRV/TXT records", () => {
|
||||
it("renders a moltbot.internal zone with gateway PTR/SRV/TXT records", () => {
|
||||
const txt = renderWideAreaGatewayZoneText({
|
||||
serial: 2025121701,
|
||||
gatewayPort: 18789,
|
||||
displayName: "Mac Studio (Clawdbot)",
|
||||
displayName: "Mac Studio (Moltbot)",
|
||||
tailnetIPv4: "100.123.224.76",
|
||||
tailnetIPv6: "fd7a:115c:a1e0::8801:e04c",
|
||||
hostLabel: "studio-london",
|
||||
instanceLabel: "studio-london",
|
||||
sshPort: 22,
|
||||
cliPath: "/opt/homebrew/bin/clawdbot",
|
||||
cliPath: "/opt/homebrew/bin/moltbot",
|
||||
});
|
||||
|
||||
expect(txt).toContain(`$ORIGIN ${WIDE_AREA_DISCOVERY_DOMAIN}`);
|
||||
expect(txt).toContain(`studio-london IN A 100.123.224.76`);
|
||||
expect(txt).toContain(`studio-london IN AAAA fd7a:115c:a1e0::8801:e04c`);
|
||||
expect(txt).toContain(`_clawdbot-gw._tcp IN PTR studio-london._clawdbot-gw._tcp`);
|
||||
expect(txt).toContain(`studio-london._clawdbot-gw._tcp IN SRV 0 0 18789 studio-london`);
|
||||
expect(txt).toContain(`displayName=Mac Studio (Clawdbot)`);
|
||||
expect(txt).toContain(`_moltbot-gw._tcp IN PTR studio-london._moltbot-gw._tcp`);
|
||||
expect(txt).toContain(`studio-london._moltbot-gw._tcp IN SRV 0 0 18789 studio-london`);
|
||||
expect(txt).toContain(`displayName=Mac Studio (Moltbot)`);
|
||||
expect(txt).toContain(`gatewayPort=18789`);
|
||||
expect(txt).toContain(`sshPort=22`);
|
||||
expect(txt).toContain(`cliPath=/opt/homebrew/bin/clawdbot`);
|
||||
expect(txt).toContain(`cliPath=/opt/homebrew/bin/moltbot`);
|
||||
});
|
||||
|
||||
it("includes tailnetDns when provided", () => {
|
||||
const txt = renderWideAreaGatewayZoneText({
|
||||
serial: 2025121701,
|
||||
gatewayPort: 18789,
|
||||
displayName: "Mac Studio (Clawdbot)",
|
||||
displayName: "Mac Studio (Moltbot)",
|
||||
tailnetIPv4: "100.123.224.76",
|
||||
tailnetDns: "peters-mac-studio-1.sheep-coho.ts.net",
|
||||
hostLabel: "studio-london",
|
||||
|
||||
@@ -4,8 +4,8 @@ import path from "node:path";
|
||||
|
||||
import { CONFIG_DIR, ensureDir } from "../utils.js";
|
||||
|
||||
export const WIDE_AREA_DISCOVERY_DOMAIN = "clawdbot.internal.";
|
||||
export const WIDE_AREA_ZONE_FILENAME = "clawdbot.internal.db";
|
||||
export const WIDE_AREA_DISCOVERY_DOMAIN = "moltbot.internal.";
|
||||
export const WIDE_AREA_ZONE_FILENAME = "moltbot.internal.db";
|
||||
|
||||
export function getWideAreaZonePath(): string {
|
||||
return path.join(CONFIG_DIR, "dns", WIDE_AREA_ZONE_FILENAME);
|
||||
@@ -51,7 +51,7 @@ function extractSerial(zoneText: string): number | null {
|
||||
}
|
||||
|
||||
function extractContentHash(zoneText: string): string | null {
|
||||
const match = zoneText.match(/^\s*;\s*clawdbot-content-hash:\s*(\S+)\s*$/m);
|
||||
const match = zoneText.match(/^\s*;\s*moltbot-content-hash:\s*(\S+)\s*$/m);
|
||||
return match?.[1] ?? null;
|
||||
}
|
||||
|
||||
@@ -80,9 +80,9 @@ export type WideAreaGatewayZoneOpts = {
|
||||
};
|
||||
|
||||
function renderZone(opts: WideAreaGatewayZoneOpts & { serial: number }): string {
|
||||
const hostname = os.hostname().split(".")[0] ?? "clawdbot";
|
||||
const hostLabel = dnsLabel(opts.hostLabel ?? hostname, "clawdbot");
|
||||
const instanceLabel = dnsLabel(opts.instanceLabel ?? `${hostname}-gateway`, "clawdbot-gw");
|
||||
const hostname = os.hostname().split(".")[0] ?? "moltbot";
|
||||
const hostLabel = dnsLabel(opts.hostLabel ?? hostname, "moltbot");
|
||||
const instanceLabel = dnsLabel(opts.instanceLabel ?? `${hostname}-gateway`, "moltbot-gw");
|
||||
|
||||
const txt = [
|
||||
`displayName=${opts.displayName.trim() || hostname}`,
|
||||
@@ -119,9 +119,9 @@ function renderZone(opts: WideAreaGatewayZoneOpts & { serial: number }): string
|
||||
records.push(`${hostLabel} IN AAAA ${opts.tailnetIPv6}`);
|
||||
}
|
||||
|
||||
records.push(`_clawdbot-gw._tcp IN PTR ${instanceLabel}._clawdbot-gw._tcp`);
|
||||
records.push(`${instanceLabel}._clawdbot-gw._tcp IN SRV 0 0 ${opts.gatewayPort} ${hostLabel}`);
|
||||
records.push(`${instanceLabel}._clawdbot-gw._tcp IN TXT ${txt.map(txtQuote).join(" ")}`);
|
||||
records.push(`_moltbot-gw._tcp IN PTR ${instanceLabel}._moltbot-gw._tcp`);
|
||||
records.push(`${instanceLabel}._moltbot-gw._tcp IN SRV 0 0 ${opts.gatewayPort} ${hostLabel}`);
|
||||
records.push(`${instanceLabel}._moltbot-gw._tcp IN TXT ${txt.map(txtQuote).join(" ")}`);
|
||||
|
||||
const contentBody = `${records.join("\n")}\n`;
|
||||
const hashBody = `${records
|
||||
@@ -131,7 +131,7 @@ function renderZone(opts: WideAreaGatewayZoneOpts & { serial: number }): string
|
||||
.join("\n")}\n`;
|
||||
const contentHash = computeContentHash(hashBody);
|
||||
|
||||
return `; clawdbot-content-hash: ${contentHash}\n${contentBody}`;
|
||||
return `; moltbot-content-hash: ${contentHash}\n${contentBody}`;
|
||||
}
|
||||
|
||||
export function renderWideAreaGatewayZoneText(
|
||||
|
||||
Reference in New Issue
Block a user