chore: rename project to clawdbot
This commit is contained in:
@@ -43,9 +43,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("_clawdis-bridge._tcp")) continue;
|
||||
if (!line || !line.includes("_clawdbot-bridge._tcp")) continue;
|
||||
if (!line.includes("Add")) continue;
|
||||
const match = line.match(/_clawdis-bridge\._tcp\.?\s+(.+)$/);
|
||||
const match = line.match(/_clawdbot-bridge\._tcp\.?\s+(.+)$/);
|
||||
if (match?.[1]) {
|
||||
instances.add(match[1].trim());
|
||||
}
|
||||
@@ -97,14 +97,14 @@ async function discoverViaDnsSd(
|
||||
timeoutMs: number,
|
||||
): Promise<GatewayBonjourBeacon[]> {
|
||||
const browse = await runCommandWithTimeout(
|
||||
["dns-sd", "-B", "_clawdis-bridge._tcp", "local."],
|
||||
["dns-sd", "-B", "_clawdbot-bridge._tcp", "local."],
|
||||
{ timeoutMs },
|
||||
);
|
||||
const instances = parseDnsSdBrowse(browse.stdout);
|
||||
const results: GatewayBonjourBeacon[] = [];
|
||||
for (const instance of instances) {
|
||||
const resolved = await runCommandWithTimeout(
|
||||
["dns-sd", "-L", instance, "_clawdis-bridge._tcp", "local."],
|
||||
["dns-sd", "-L", instance, "_clawdbot-bridge._tcp", "local."],
|
||||
{ timeoutMs },
|
||||
);
|
||||
const parsed = parseDnsSdResolve(resolved.stdout, instance);
|
||||
@@ -120,9 +120,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("_clawdis-bridge._tcp")) {
|
||||
if (line.startsWith("=") && line.includes("_clawdbot-bridge._tcp")) {
|
||||
if (current) results.push(current);
|
||||
const marker = " _clawdis-bridge._tcp";
|
||||
const marker = " _clawdbot-bridge._tcp";
|
||||
const idx = line.indexOf(marker);
|
||||
const left = idx >= 0 ? line.slice(0, idx).trim() : line;
|
||||
const parts = left.split(/\s+/);
|
||||
@@ -171,7 +171,7 @@ async function discoverViaAvahi(
|
||||
timeoutMs: number,
|
||||
): Promise<GatewayBonjourBeacon[]> {
|
||||
const browse = await runCommandWithTimeout(
|
||||
["avahi-browse", "-rt", "_clawdis-bridge._tcp"],
|
||||
["avahi-browse", "-rt", "_clawdbot-bridge._tcp"],
|
||||
{ timeoutMs },
|
||||
);
|
||||
return parseAvahiBrowse(browse.stdout);
|
||||
|
||||
@@ -100,14 +100,14 @@ describe("gateway bonjour advertiser", () => {
|
||||
sshPort: 2222,
|
||||
bridgePort: 18790,
|
||||
tailnetDns: "host.tailnet.ts.net",
|
||||
cliPath: "/opt/homebrew/bin/clawdis",
|
||||
cliPath: "/opt/homebrew/bin/clawdbot",
|
||||
});
|
||||
|
||||
expect(createService).toHaveBeenCalledTimes(1);
|
||||
const [bridgeCall] = createService.mock.calls as Array<
|
||||
[Record<string, unknown>]
|
||||
>;
|
||||
expect(bridgeCall?.[0]?.type).toBe("clawdis-bridge");
|
||||
expect(bridgeCall?.[0]?.type).toBe("clawdbot-bridge");
|
||||
expect(bridgeCall?.[0]?.port).toBe(18790);
|
||||
expect(bridgeCall?.[0]?.domain).toBe("local");
|
||||
expect(bridgeCall?.[0]?.hostname).toBe("test-host");
|
||||
@@ -121,7 +121,7 @@ describe("gateway bonjour advertiser", () => {
|
||||
"2222",
|
||||
);
|
||||
expect((bridgeCall?.[0]?.txt as Record<string, string>)?.cliPath).toBe(
|
||||
"/opt/homebrew/bin/clawdis",
|
||||
"/opt/homebrew/bin/clawdbot",
|
||||
);
|
||||
expect((bridgeCall?.[0]?.txt as Record<string, string>)?.transport).toBe(
|
||||
"bridge",
|
||||
@@ -297,7 +297,7 @@ describe("gateway bonjour advertiser", () => {
|
||||
});
|
||||
|
||||
const [bridgeCall] = createService.mock.calls as Array<[ServiceCall]>;
|
||||
expect(bridgeCall?.[0]?.name).toBe("Mac (Clawdis)");
|
||||
expect(bridgeCall?.[0]?.name).toBe("Mac (Clawdbot)");
|
||||
expect(bridgeCall?.[0]?.domain).toBe("local");
|
||||
expect(bridgeCall?.[0]?.hostname).toBe("Mac");
|
||||
expect((bridgeCall?.[0]?.txt as Record<string, string>)?.lanHost).toBe(
|
||||
|
||||
@@ -18,7 +18,7 @@ export type GatewayBonjourAdvertiseOpts = {
|
||||
};
|
||||
|
||||
function isDisabledByEnv() {
|
||||
if (process.env.CLAWDIS_DISABLE_BONJOUR === "1") return true;
|
||||
if (process.env.CLAWDBOT_DISABLE_BONJOUR === "1") return true;
|
||||
if (process.env.NODE_ENV === "test") return true;
|
||||
if (process.env.VITEST) return true;
|
||||
return false;
|
||||
@@ -26,12 +26,12 @@ function isDisabledByEnv() {
|
||||
|
||||
function safeServiceName(name: string) {
|
||||
const trimmed = name.trim();
|
||||
return trimmed.length > 0 ? trimmed : "Clawdis";
|
||||
return trimmed.length > 0 ? trimmed : "Clawdbot";
|
||||
}
|
||||
|
||||
function prettifyInstanceName(name: string) {
|
||||
const normalized = name.trim().replace(/\s+/g, " ");
|
||||
return normalized.replace(/\s+\(Clawdis\)\s*$/i, "").trim() || normalized;
|
||||
return normalized.replace(/\s+\(Clawdbot\)\s*$/i, "").trim() || normalized;
|
||||
}
|
||||
|
||||
type BonjourService = {
|
||||
@@ -94,11 +94,11 @@ export async function startGatewayBonjourAdvertiser(
|
||||
.hostname()
|
||||
.replace(/\.local$/i, "")
|
||||
.split(".")[0]
|
||||
.trim() || "clawdis";
|
||||
.trim() || "clawdbot";
|
||||
const instanceName =
|
||||
typeof opts.instanceName === "string" && opts.instanceName.trim()
|
||||
? opts.instanceName.trim()
|
||||
: `${hostname} (Clawdis)`;
|
||||
: `${hostname} (Clawdbot)`;
|
||||
const displayName = prettifyInstanceName(instanceName);
|
||||
|
||||
const txtBase: Record<string, string> = {
|
||||
@@ -126,7 +126,7 @@ export async function startGatewayBonjourAdvertiser(
|
||||
if (typeof opts.bridgePort === "number" && opts.bridgePort > 0) {
|
||||
const bridge = responder.createService({
|
||||
name: safeServiceName(instanceName),
|
||||
type: "clawdis-bridge",
|
||||
type: "clawdbot-bridge",
|
||||
protocol: Protocol.TCP,
|
||||
port: opts.bridgePort,
|
||||
domain: "local",
|
||||
|
||||
@@ -61,13 +61,13 @@ describe("node bridge server", () => {
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
process.env.CLAWDIS_ENABLE_BRIDGE_IN_TESTS = "1";
|
||||
baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-bridge-test-"));
|
||||
process.env.CLAWDBOT_ENABLE_BRIDGE_IN_TESTS = "1";
|
||||
baseDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-bridge-test-"));
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await fs.rm(baseDir, { recursive: true, force: true });
|
||||
delete process.env.CLAWDIS_ENABLE_BRIDGE_IN_TESTS;
|
||||
delete process.env.CLAWDBOT_ENABLE_BRIDGE_IN_TESTS;
|
||||
});
|
||||
|
||||
it("rejects hello when not paired", async () => {
|
||||
|
||||
@@ -171,7 +171,7 @@ async function sleep(ms: number) {
|
||||
export async function startNodeBridgeServer(
|
||||
opts: NodeBridgeServerOpts,
|
||||
): Promise<NodeBridgeServer> {
|
||||
if (isTestEnv() && process.env.CLAWDIS_ENABLE_BRIDGE_IN_TESTS !== "1") {
|
||||
if (isTestEnv() && process.env.CLAWDBOT_ENABLE_BRIDGE_IN_TESTS !== "1") {
|
||||
return {
|
||||
port: 0,
|
||||
close: async () => {},
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from "node:path";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { HEARTBEAT_PROMPT } from "../auto-reply/heartbeat.js";
|
||||
import * as replyModule from "../auto-reply/reply.js";
|
||||
import type { ClawdisConfig } from "../config/config.js";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import {
|
||||
resolveHeartbeatDeliveryTarget,
|
||||
resolveHeartbeatIntervalMs,
|
||||
@@ -42,7 +42,7 @@ describe("resolveHeartbeatPrompt", () => {
|
||||
});
|
||||
|
||||
it("uses a trimmed override when configured", () => {
|
||||
const cfg: ClawdisConfig = {
|
||||
const cfg: ClawdbotConfig = {
|
||||
agent: { heartbeat: { prompt: " ping " } },
|
||||
};
|
||||
expect(resolveHeartbeatPrompt(cfg)).toBe("ping");
|
||||
@@ -56,7 +56,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
};
|
||||
|
||||
it("respects target none", () => {
|
||||
const cfg: ClawdisConfig = {
|
||||
const cfg: ClawdbotConfig = {
|
||||
agent: { heartbeat: { target: "none" } },
|
||||
};
|
||||
expect(resolveHeartbeatDeliveryTarget({ cfg, entry: baseEntry })).toEqual({
|
||||
@@ -66,7 +66,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
it("uses last route by default", () => {
|
||||
const cfg: ClawdisConfig = {};
|
||||
const cfg: ClawdbotConfig = {};
|
||||
const entry = {
|
||||
...baseEntry,
|
||||
lastChannel: "whatsapp" as const,
|
||||
@@ -79,7 +79,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
it("skips when last route is webchat", () => {
|
||||
const cfg: ClawdisConfig = {};
|
||||
const cfg: ClawdbotConfig = {};
|
||||
const entry = {
|
||||
...baseEntry,
|
||||
lastChannel: "webchat" as const,
|
||||
@@ -92,7 +92,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
it("applies allowFrom fallback for WhatsApp targets", () => {
|
||||
const cfg: ClawdisConfig = {
|
||||
const cfg: ClawdbotConfig = {
|
||||
agent: { heartbeat: { target: "whatsapp", to: "+1999" } },
|
||||
whatsapp: { allowFrom: ["+1555", "+1666"] },
|
||||
};
|
||||
@@ -109,7 +109,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
it("keeps explicit telegram targets", () => {
|
||||
const cfg: ClawdisConfig = {
|
||||
const cfg: ClawdbotConfig = {
|
||||
agent: { heartbeat: { target: "telegram", to: "123" } },
|
||||
};
|
||||
expect(resolveHeartbeatDeliveryTarget({ cfg, entry: baseEntry })).toEqual({
|
||||
@@ -121,7 +121,7 @@ describe("resolveHeartbeatDeliveryTarget", () => {
|
||||
|
||||
describe("runHeartbeatOnce", () => {
|
||||
it("uses the last non-empty payload for delivery", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
@@ -141,7 +141,7 @@ describe("runHeartbeatOnce", () => {
|
||||
),
|
||||
);
|
||||
|
||||
const cfg: ClawdisConfig = {
|
||||
const cfg: ClawdbotConfig = {
|
||||
agent: {
|
||||
heartbeat: { every: "5m", target: "whatsapp", to: "+1555" },
|
||||
},
|
||||
@@ -182,7 +182,7 @@ describe("runHeartbeatOnce", () => {
|
||||
});
|
||||
|
||||
it("skips WhatsApp delivery when not linked or running", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-hb-"));
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-hb-"));
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
|
||||
try {
|
||||
@@ -202,7 +202,7 @@ describe("runHeartbeatOnce", () => {
|
||||
),
|
||||
);
|
||||
|
||||
const cfg: ClawdisConfig = {
|
||||
const cfg: ClawdbotConfig = {
|
||||
agent: {
|
||||
heartbeat: { every: "5m", target: "whatsapp", to: "+1555" },
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
import { getReplyFromConfig } from "../auto-reply/reply.js";
|
||||
import type { ReplyPayload } from "../auto-reply/types.js";
|
||||
import { parseDurationMs } from "../cli/parse-duration.js";
|
||||
import type { ClawdisConfig } from "../config/config.js";
|
||||
import type { ClawdbotConfig } from "../config/config.js";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import {
|
||||
loadSessionStore,
|
||||
@@ -79,7 +79,7 @@ export function setHeartbeatsEnabled(enabled: boolean) {
|
||||
}
|
||||
|
||||
export function resolveHeartbeatIntervalMs(
|
||||
cfg: ClawdisConfig,
|
||||
cfg: ClawdbotConfig,
|
||||
overrideEvery?: string,
|
||||
) {
|
||||
const raw = overrideEvery ?? cfg.agent?.heartbeat?.every;
|
||||
@@ -96,13 +96,13 @@ export function resolveHeartbeatIntervalMs(
|
||||
return ms;
|
||||
}
|
||||
|
||||
export function resolveHeartbeatPrompt(cfg: ClawdisConfig) {
|
||||
export function resolveHeartbeatPrompt(cfg: ClawdbotConfig) {
|
||||
const raw = cfg.agent?.heartbeat?.prompt;
|
||||
const trimmed = typeof raw === "string" ? raw.trim() : "";
|
||||
return trimmed || HEARTBEAT_PROMPT;
|
||||
}
|
||||
|
||||
function resolveHeartbeatSession(cfg: ClawdisConfig) {
|
||||
function resolveHeartbeatSession(cfg: ClawdbotConfig) {
|
||||
const sessionCfg = cfg.session;
|
||||
const scope = sessionCfg?.scope ?? "per-sender";
|
||||
const mainKey = (sessionCfg?.mainKey ?? "main").trim() || "main";
|
||||
@@ -164,7 +164,7 @@ function resolveHeartbeatSender(params: {
|
||||
}
|
||||
|
||||
async function resolveWhatsAppReadiness(
|
||||
cfg: ClawdisConfig,
|
||||
cfg: ClawdbotConfig,
|
||||
deps?: HeartbeatDeps,
|
||||
): Promise<{ ok: boolean; reason: string }> {
|
||||
if (cfg.web?.enabled === false) {
|
||||
@@ -184,7 +184,7 @@ async function resolveWhatsAppReadiness(
|
||||
}
|
||||
|
||||
export function resolveHeartbeatDeliveryTarget(params: {
|
||||
cfg: ClawdisConfig;
|
||||
cfg: ClawdbotConfig;
|
||||
entry?: SessionEntry;
|
||||
}): HeartbeatDeliveryTarget {
|
||||
const { cfg, entry } = params;
|
||||
@@ -417,7 +417,7 @@ async function deliverHeartbeatReply(params: {
|
||||
}
|
||||
|
||||
export async function runHeartbeatOnce(opts: {
|
||||
cfg?: ClawdisConfig;
|
||||
cfg?: ClawdbotConfig;
|
||||
reason?: string;
|
||||
deps?: HeartbeatDeps;
|
||||
}): Promise<HeartbeatRunResult> {
|
||||
@@ -568,7 +568,7 @@ export async function runHeartbeatOnce(opts: {
|
||||
}
|
||||
|
||||
export function startHeartbeatRunner(opts: {
|
||||
cfg?: ClawdisConfig;
|
||||
cfg?: ClawdbotConfig;
|
||||
runtime?: RuntimeEnv;
|
||||
abortSignal?: AbortSignal;
|
||||
}) {
|
||||
|
||||
@@ -28,7 +28,7 @@ describe("isMainModule", () => {
|
||||
it("returns false when running under PM2 but this module is imported", () => {
|
||||
expect(
|
||||
isMainModule({
|
||||
currentFile: "/repo/node_modules/clawdis/dist/index.js",
|
||||
currentFile: "/repo/node_modules/clawdbot/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() || "clawdis"
|
||||
.trim() || "clawdbot"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ type NodePairingStateFile = {
|
||||
const PENDING_TTL_MS = 5 * 60 * 1000;
|
||||
|
||||
function defaultBaseDir() {
|
||||
return path.join(os.homedir(), ".clawdis");
|
||||
return path.join(os.homedir(), ".clawdbot");
|
||||
}
|
||||
|
||||
function resolvePaths(baseDir?: string) {
|
||||
|
||||
@@ -4,24 +4,24 @@ import path from "node:path";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { ensureClawdisCliOnPath } from "./path-env.js";
|
||||
import { ensureClawdbotCliOnPath } from "./path-env.js";
|
||||
|
||||
describe("ensureClawdisCliOnPath", () => {
|
||||
it("prepends the bundled Relay dir when a sibling clawdis exists", async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-path-"));
|
||||
describe("ensureClawdbotCliOnPath", () => {
|
||||
it("prepends the bundled Relay dir when a sibling clawdbot exists", async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-path-"));
|
||||
try {
|
||||
const relayDir = path.join(tmp, "Relay");
|
||||
await fs.mkdir(relayDir, { recursive: true });
|
||||
const cliPath = path.join(relayDir, "clawdis");
|
||||
const cliPath = path.join(relayDir, "clawdbot");
|
||||
await fs.writeFile(cliPath, "#!/bin/sh\necho ok\n", "utf-8");
|
||||
await fs.chmod(cliPath, 0o755);
|
||||
|
||||
const originalPath = process.env.PATH;
|
||||
const originalFlag = process.env.CLAWDIS_PATH_BOOTSTRAPPED;
|
||||
const originalFlag = process.env.CLAWDBOT_PATH_BOOTSTRAPPED;
|
||||
process.env.PATH = "/usr/bin";
|
||||
delete process.env.CLAWDIS_PATH_BOOTSTRAPPED;
|
||||
delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED;
|
||||
try {
|
||||
ensureClawdisCliOnPath({
|
||||
ensureClawdbotCliOnPath({
|
||||
execPath: cliPath,
|
||||
cwd: tmp,
|
||||
homeDir: tmp,
|
||||
@@ -32,8 +32,8 @@ describe("ensureClawdisCliOnPath", () => {
|
||||
} finally {
|
||||
process.env.PATH = originalPath;
|
||||
if (originalFlag === undefined)
|
||||
delete process.env.CLAWDIS_PATH_BOOTSTRAPPED;
|
||||
else process.env.CLAWDIS_PATH_BOOTSTRAPPED = originalFlag;
|
||||
delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED;
|
||||
else process.env.CLAWDBOT_PATH_BOOTSTRAPPED = originalFlag;
|
||||
}
|
||||
} finally {
|
||||
await fs.rm(tmp, { recursive: true, force: true });
|
||||
@@ -42,11 +42,11 @@ describe("ensureClawdisCliOnPath", () => {
|
||||
|
||||
it("is idempotent", () => {
|
||||
const originalPath = process.env.PATH;
|
||||
const originalFlag = process.env.CLAWDIS_PATH_BOOTSTRAPPED;
|
||||
const originalFlag = process.env.CLAWDBOT_PATH_BOOTSTRAPPED;
|
||||
process.env.PATH = "/bin";
|
||||
process.env.CLAWDIS_PATH_BOOTSTRAPPED = "1";
|
||||
process.env.CLAWDBOT_PATH_BOOTSTRAPPED = "1";
|
||||
try {
|
||||
ensureClawdisCliOnPath({
|
||||
ensureClawdbotCliOnPath({
|
||||
execPath: "/tmp/does-not-matter",
|
||||
cwd: "/tmp",
|
||||
homeDir: "/tmp",
|
||||
@@ -56,26 +56,26 @@ describe("ensureClawdisCliOnPath", () => {
|
||||
} finally {
|
||||
process.env.PATH = originalPath;
|
||||
if (originalFlag === undefined)
|
||||
delete process.env.CLAWDIS_PATH_BOOTSTRAPPED;
|
||||
else process.env.CLAWDIS_PATH_BOOTSTRAPPED = originalFlag;
|
||||
delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED;
|
||||
else process.env.CLAWDBOT_PATH_BOOTSTRAPPED = originalFlag;
|
||||
}
|
||||
});
|
||||
|
||||
it("prepends mise shims when available", async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-path-"));
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-path-"));
|
||||
const originalPath = process.env.PATH;
|
||||
const originalFlag = process.env.CLAWDIS_PATH_BOOTSTRAPPED;
|
||||
const originalFlag = process.env.CLAWDBOT_PATH_BOOTSTRAPPED;
|
||||
const originalMiseDataDir = process.env.MISE_DATA_DIR;
|
||||
try {
|
||||
const relayDir = path.join(tmp, "Relay");
|
||||
await fs.mkdir(relayDir, { recursive: true });
|
||||
const relayCli = path.join(relayDir, "clawdis");
|
||||
const relayCli = path.join(relayDir, "clawdbot");
|
||||
await fs.writeFile(relayCli, "#!/bin/sh\necho ok\n", "utf-8");
|
||||
await fs.chmod(relayCli, 0o755);
|
||||
|
||||
const localBinDir = path.join(tmp, "node_modules", ".bin");
|
||||
await fs.mkdir(localBinDir, { recursive: true });
|
||||
const localCli = path.join(localBinDir, "clawdis");
|
||||
const localCli = path.join(localBinDir, "clawdbot");
|
||||
await fs.writeFile(localCli, "#!/bin/sh\necho ok\n", "utf-8");
|
||||
await fs.chmod(localCli, 0o755);
|
||||
|
||||
@@ -84,9 +84,9 @@ describe("ensureClawdisCliOnPath", () => {
|
||||
await fs.mkdir(shimsDir, { recursive: true });
|
||||
process.env.MISE_DATA_DIR = miseDataDir;
|
||||
process.env.PATH = "/usr/bin";
|
||||
delete process.env.CLAWDIS_PATH_BOOTSTRAPPED;
|
||||
delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED;
|
||||
|
||||
ensureClawdisCliOnPath({
|
||||
ensureClawdbotCliOnPath({
|
||||
execPath: relayCli,
|
||||
cwd: tmp,
|
||||
homeDir: tmp,
|
||||
@@ -104,8 +104,8 @@ describe("ensureClawdisCliOnPath", () => {
|
||||
} finally {
|
||||
process.env.PATH = originalPath;
|
||||
if (originalFlag === undefined)
|
||||
delete process.env.CLAWDIS_PATH_BOOTSTRAPPED;
|
||||
else process.env.CLAWDIS_PATH_BOOTSTRAPPED = originalFlag;
|
||||
delete process.env.CLAWDBOT_PATH_BOOTSTRAPPED;
|
||||
else process.env.CLAWDBOT_PATH_BOOTSTRAPPED = originalFlag;
|
||||
if (originalMiseDataDir === undefined) delete process.env.MISE_DATA_DIR;
|
||||
else process.env.MISE_DATA_DIR = originalMiseDataDir;
|
||||
await fs.rm(tmp, { recursive: true, force: true });
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
type EnsureClawdisPathOpts = {
|
||||
type EnsureClawdbotPathOpts = {
|
||||
execPath?: string;
|
||||
cwd?: string;
|
||||
homeDir?: string;
|
||||
@@ -47,7 +47,7 @@ function mergePath(params: { existing: string; prepend: string[] }): string {
|
||||
return merged.join(path.delimiter);
|
||||
}
|
||||
|
||||
function candidateBinDirs(opts: EnsureClawdisPathOpts): string[] {
|
||||
function candidateBinDirs(opts: EnsureClawdbotPathOpts): string[] {
|
||||
const execPath = opts.execPath ?? process.execPath;
|
||||
const cwd = opts.cwd ?? process.cwd();
|
||||
const homeDir = opts.homeDir ?? os.homedir();
|
||||
@@ -55,19 +55,19 @@ function candidateBinDirs(opts: EnsureClawdisPathOpts): string[] {
|
||||
|
||||
const candidates: string[] = [];
|
||||
|
||||
// Bun bundled (macOS app): `clawdis` lives in the Relay dir (process.execPath).
|
||||
// Bun bundled (macOS app): `clawdbot` lives in the Relay dir (process.execPath).
|
||||
try {
|
||||
const execDir = path.dirname(execPath);
|
||||
const siblingClawdis = path.join(execDir, "clawdis");
|
||||
if (isExecutable(siblingClawdis)) candidates.push(execDir);
|
||||
const siblingClawdbot = path.join(execDir, "clawdbot");
|
||||
if (isExecutable(siblingClawdbot)) candidates.push(execDir);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// Project-local installs (best effort): if a `node_modules/.bin/clawdis` exists near cwd,
|
||||
// Project-local installs (best effort): if a `node_modules/.bin/clawdbot` 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, "clawdis")))
|
||||
if (isExecutable(path.join(localBinDir, "clawdbot")))
|
||||
candidates.push(localBinDir);
|
||||
|
||||
const miseDataDir =
|
||||
@@ -90,12 +90,12 @@ function candidateBinDirs(opts: EnsureClawdisPathOpts): string[] {
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort PATH bootstrap so skills that require the `clawdis` CLI can run
|
||||
* Best-effort PATH bootstrap so skills that require the `clawdbot` CLI can run
|
||||
* under launchd/minimal environments (and inside the macOS bun bundle).
|
||||
*/
|
||||
export function ensureClawdisCliOnPath(opts: EnsureClawdisPathOpts = {}) {
|
||||
if (process.env.CLAWDIS_PATH_BOOTSTRAPPED === "1") return;
|
||||
process.env.CLAWDIS_PATH_BOOTSTRAPPED = "1";
|
||||
export function ensureClawdbotCliOnPath(opts: EnsureClawdbotPathOpts = {}) {
|
||||
if (process.env.CLAWDBOT_PATH_BOOTSTRAPPED === "1") return;
|
||||
process.env.CLAWDBOT_PATH_BOOTSTRAPPED = "1";
|
||||
|
||||
const existing = opts.pathEnv ?? process.env.PATH ?? "";
|
||||
const prepend = candidateBinDirs(opts);
|
||||
|
||||
@@ -85,10 +85,10 @@ export async function handlePortError(
|
||||
if (details) {
|
||||
runtime.error(info("Port listener details:"));
|
||||
runtime.error(details);
|
||||
if (/clawdis|src\/index\.ts|dist\/index\.js/.test(details)) {
|
||||
if (/clawdbot|src\/index\.ts|dist\/index\.js/.test(details)) {
|
||||
runtime.error(
|
||||
warn(
|
||||
"It looks like another clawdis instance is already running. Stop it or pick a different port.",
|
||||
"It looks like another clawdbot instance is already running. Stop it or pick a different port.",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import chalk from "chalk";
|
||||
import { type ClawdisConfig, loadConfig } from "../config/config.js";
|
||||
import { type ClawdbotConfig, loadConfig } from "../config/config.js";
|
||||
import { resolveTelegramToken } from "../telegram/token.js";
|
||||
import { normalizeE164 } from "../utils.js";
|
||||
import {
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
} from "../web/session.js";
|
||||
|
||||
export async function buildProviderSummary(
|
||||
cfg?: ClawdisConfig,
|
||||
cfg?: ClawdbotConfig,
|
||||
): Promise<string[]> {
|
||||
const effective = cfg ?? loadConfig();
|
||||
const lines: string[] = [];
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
const DEFAULT_LAUNCHD_LABEL = "com.clawdis.mac";
|
||||
const DEFAULT_SYSTEMD_UNIT = "clawdis-gateway.service";
|
||||
const DEFAULT_LAUNCHD_LABEL = "com.clawdbot.mac";
|
||||
const DEFAULT_SYSTEMD_UNIT = "clawdbot-gateway.service";
|
||||
|
||||
export function triggerClawdisRestart():
|
||||
export function triggerClawdbotRestart():
|
||||
| "launchctl"
|
||||
| "systemd"
|
||||
| "supervisor" {
|
||||
if (process.platform !== "darwin") {
|
||||
if (process.platform === "linux") {
|
||||
const unit = process.env.CLAWDIS_SYSTEMD_UNIT || DEFAULT_SYSTEMD_UNIT;
|
||||
const unit = process.env.CLAWDBOT_SYSTEMD_UNIT || DEFAULT_SYSTEMD_UNIT;
|
||||
const userRestart = spawnSync("systemctl", ["--user", "restart", unit], {
|
||||
stdio: "ignore",
|
||||
});
|
||||
@@ -27,7 +27,7 @@ export function triggerClawdisRestart():
|
||||
return "supervisor";
|
||||
}
|
||||
|
||||
const label = process.env.CLAWDIS_LAUNCHD_LABEL || DEFAULT_LAUNCHD_LABEL;
|
||||
const label = process.env.CLAWDBOT_LAUNCHD_LABEL || DEFAULT_LAUNCHD_LABEL;
|
||||
const uid =
|
||||
typeof process.getuid === "function" ? process.getuid() : undefined;
|
||||
const target = uid !== undefined ? `gui/${uid}/${label}` : label;
|
||||
|
||||
@@ -73,11 +73,11 @@ export function assertSupportedRuntime(
|
||||
|
||||
runtime.error(
|
||||
[
|
||||
"clawdis requires Node >=22.0.0.",
|
||||
"clawdbot 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 clawdis.",
|
||||
"Upgrade Node and re-run clawdbot.",
|
||||
].join("\n"),
|
||||
);
|
||||
runtime.exit(1);
|
||||
|
||||
@@ -12,7 +12,7 @@ describe("system-presence", () => {
|
||||
const instanceIdLower = instanceIdUpper.toLowerCase();
|
||||
|
||||
upsertPresence(instanceIdUpper, {
|
||||
host: "clawdis",
|
||||
host: "clawdbot",
|
||||
mode: "app",
|
||||
instanceId: instanceIdUpper,
|
||||
reason: "connect",
|
||||
|
||||
@@ -57,7 +57,7 @@ function initSelfPresence() {
|
||||
const host = os.hostname();
|
||||
const ip = resolvePrimaryIPv4() ?? undefined;
|
||||
const version =
|
||||
process.env.CLAWDIS_VERSION ?? process.env.npm_package_version ?? "unknown";
|
||||
process.env.CLAWDBOT_VERSION ?? process.env.npm_package_version ?? "unknown";
|
||||
const modelIdentifier = (() => {
|
||||
const p = os.platform();
|
||||
if (p === "darwin") {
|
||||
|
||||
@@ -176,7 +176,7 @@ export async function ensureFunnel(
|
||||
);
|
||||
runtime.error(
|
||||
info(
|
||||
"Tip: Funnel is optional for CLAWDIS. You can keep running the web gateway without it: `pnpm clawdis gateway`",
|
||||
"Tip: Funnel is optional for CLAWDBOT. You can keep running the web gateway without it: `pnpm clawdbot gateway`",
|
||||
),
|
||||
);
|
||||
if (shouldLogVerbose()) {
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
describe("voicewake store", () => {
|
||||
it("returns defaults when missing", async () => {
|
||||
const baseDir = await fs.mkdtemp(
|
||||
path.join(os.tmpdir(), "clawdis-voicewake-"),
|
||||
path.join(os.tmpdir(), "clawdbot-voicewake-"),
|
||||
);
|
||||
const cfg = await loadVoiceWakeConfig(baseDir);
|
||||
expect(cfg.triggers).toEqual(defaultVoiceWakeTriggers());
|
||||
@@ -22,7 +22,7 @@ describe("voicewake store", () => {
|
||||
|
||||
it("sanitizes and persists triggers", async () => {
|
||||
const baseDir = await fs.mkdtemp(
|
||||
path.join(os.tmpdir(), "clawdis-voicewake-"),
|
||||
path.join(os.tmpdir(), "clawdbot-voicewake-"),
|
||||
);
|
||||
const saved = await setVoiceWakeTriggers(
|
||||
[" hi ", "", " there "],
|
||||
@@ -38,7 +38,7 @@ describe("voicewake store", () => {
|
||||
|
||||
it("falls back to defaults when triggers empty", async () => {
|
||||
const baseDir = await fs.mkdtemp(
|
||||
path.join(os.tmpdir(), "clawdis-voicewake-"),
|
||||
path.join(os.tmpdir(), "clawdbot-voicewake-"),
|
||||
);
|
||||
const saved = await setVoiceWakeTriggers(["", " "], baseDir);
|
||||
expect(saved.triggers).toEqual(defaultVoiceWakeTriggers());
|
||||
|
||||
@@ -11,7 +11,7 @@ export type VoiceWakeConfig = {
|
||||
const DEFAULT_TRIGGERS = ["clawd", "claude", "computer"];
|
||||
|
||||
function defaultBaseDir() {
|
||||
return path.join(os.homedir(), ".clawdis");
|
||||
return path.join(os.homedir(), ".clawdbot");
|
||||
}
|
||||
|
||||
function resolvePath(baseDir?: string) {
|
||||
|
||||
@@ -6,11 +6,11 @@ import {
|
||||
} from "./widearea-dns.js";
|
||||
|
||||
describe("wide-area DNS-SD zone rendering", () => {
|
||||
it("renders a clawdis.internal zone with bridge PTR/SRV/TXT records", () => {
|
||||
it("renders a clawdbot.internal zone with bridge PTR/SRV/TXT records", () => {
|
||||
const txt = renderWideAreaBridgeZoneText({
|
||||
serial: 2025121701,
|
||||
bridgePort: 18790,
|
||||
displayName: "Mac Studio (Clawdis)",
|
||||
displayName: "Mac Studio (Clawdbot)",
|
||||
tailnetIPv4: "100.123.224.76",
|
||||
tailnetIPv6: "fd7a:115c:a1e0::8801:e04c",
|
||||
hostLabel: "studio-london",
|
||||
@@ -21,19 +21,19 @@ describe("wide-area DNS-SD zone rendering", () => {
|
||||
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(
|
||||
`_clawdis-bridge._tcp IN PTR studio-london._clawdis-bridge._tcp`,
|
||||
`_clawdbot-bridge._tcp IN PTR studio-london._clawdbot-bridge._tcp`,
|
||||
);
|
||||
expect(txt).toContain(
|
||||
`studio-london._clawdis-bridge._tcp IN SRV 0 0 18790 studio-london`,
|
||||
`studio-london._clawdbot-bridge._tcp IN SRV 0 0 18790 studio-london`,
|
||||
);
|
||||
expect(txt).toContain(`displayName=Mac Studio (Clawdis)`);
|
||||
expect(txt).toContain(`displayName=Mac Studio (Clawdbot)`);
|
||||
});
|
||||
|
||||
it("includes tailnetDns when provided", () => {
|
||||
const txt = renderWideAreaBridgeZoneText({
|
||||
serial: 2025121701,
|
||||
bridgePort: 18790,
|
||||
displayName: "Mac Studio (Clawdis)",
|
||||
displayName: "Mac Studio (Clawdbot)",
|
||||
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 = "clawdis.internal.";
|
||||
export const WIDE_AREA_ZONE_FILENAME = "clawdis.internal.db";
|
||||
export const WIDE_AREA_DISCOVERY_DOMAIN = "clawdbot.internal.";
|
||||
export const WIDE_AREA_ZONE_FILENAME = "clawdbot.internal.db";
|
||||
|
||||
export function getWideAreaZonePath(): string {
|
||||
return path.join(CONFIG_DIR, "dns", WIDE_AREA_ZONE_FILENAME);
|
||||
@@ -54,7 +54,7 @@ function extractSerial(zoneText: string): number | null {
|
||||
}
|
||||
|
||||
function extractContentHash(zoneText: string): string | null {
|
||||
const match = zoneText.match(/^\s*;\s*clawdis-content-hash:\s*(\S+)\s*$/m);
|
||||
const match = zoneText.match(/^\s*;\s*clawdbot-content-hash:\s*(\S+)\s*$/m);
|
||||
return match?.[1] ?? null;
|
||||
}
|
||||
|
||||
@@ -79,11 +79,11 @@ export type WideAreaBridgeZoneOpts = {
|
||||
};
|
||||
|
||||
function renderZone(opts: WideAreaBridgeZoneOpts & { serial: number }): string {
|
||||
const hostname = os.hostname().split(".")[0] ?? "clawdis";
|
||||
const hostLabel = dnsLabel(opts.hostLabel ?? hostname, "clawdis");
|
||||
const hostname = os.hostname().split(".")[0] ?? "clawdbot";
|
||||
const hostLabel = dnsLabel(opts.hostLabel ?? hostname, "clawdbot");
|
||||
const instanceLabel = dnsLabel(
|
||||
opts.instanceLabel ?? `${hostname}-bridge`,
|
||||
"clawdis-bridge",
|
||||
"clawdbot-bridge",
|
||||
);
|
||||
|
||||
const txt = [
|
||||
@@ -109,13 +109,13 @@ function renderZone(opts: WideAreaBridgeZoneOpts & { serial: number }): string {
|
||||
}
|
||||
|
||||
records.push(
|
||||
`_clawdis-bridge._tcp IN PTR ${instanceLabel}._clawdis-bridge._tcp`,
|
||||
`_clawdbot-bridge._tcp IN PTR ${instanceLabel}._clawdbot-bridge._tcp`,
|
||||
);
|
||||
records.push(
|
||||
`${instanceLabel}._clawdis-bridge._tcp IN SRV 0 0 ${opts.bridgePort} ${hostLabel}`,
|
||||
`${instanceLabel}._clawdbot-bridge._tcp IN SRV 0 0 ${opts.bridgePort} ${hostLabel}`,
|
||||
);
|
||||
records.push(
|
||||
`${instanceLabel}._clawdis-bridge._tcp IN TXT ${txt.map(txtQuote).join(" ")}`,
|
||||
`${instanceLabel}._clawdbot-bridge._tcp IN TXT ${txt.map(txtQuote).join(" ")}`,
|
||||
);
|
||||
|
||||
const contentBody = `${records.join("\n")}\n`;
|
||||
@@ -128,7 +128,7 @@ function renderZone(opts: WideAreaBridgeZoneOpts & { serial: number }): string {
|
||||
.join("\n")}\n`;
|
||||
const contentHash = computeContentHash(hashBody);
|
||||
|
||||
return `; clawdis-content-hash: ${contentHash}\n${contentBody}`;
|
||||
return `; clawdbot-content-hash: ${contentHash}\n${contentBody}`;
|
||||
}
|
||||
|
||||
export function renderWideAreaBridgeZoneText(
|
||||
|
||||
Reference in New Issue
Block a user