diff --git a/src/cli/program.ts b/src/cli/program.ts
index e74851b73..cb67d9421 100644
--- a/src/cli/program.ts
+++ b/src/cli/program.ts
@@ -134,7 +134,9 @@ export function buildProgram() {
program
.command("onboard")
- .description("Interactive wizard to set up the gateway, workspace, and skills")
+ .description(
+ "Interactive wizard to set up the gateway, workspace, and skills",
+ )
.option("--workspace
", "Agent workspace directory (default: ~/clawd)")
.option("--non-interactive", "Run without prompts", false)
.option("--mode ", "Wizard mode: local|remote")
@@ -166,7 +168,10 @@ export function buildProgram() {
| "skip"
| undefined,
anthropicApiKey: opts.anthropicApiKey as string | undefined,
- gatewayPort: Number.parseInt(String(opts.gatewayPort ?? "18789"), 10),
+ gatewayPort: Number.parseInt(
+ String(opts.gatewayPort ?? "18789"),
+ 10,
+ ),
gatewayBind: opts.gatewayBind as
| "loopback"
| "lan"
diff --git a/src/commands/onboard.ts b/src/commands/onboard.ts
index 8dcc6ffad..aa07284d2 100644
--- a/src/commands/onboard.ts
+++ b/src/commands/onboard.ts
@@ -7,23 +7,22 @@ import {
confirm,
intro,
isCancel,
+ multiselect,
note,
outro,
select,
spinner,
text,
- multiselect,
} from "@clack/prompts";
import { loginAnthropic, type OAuthCredentials } from "@mariozechner/pi-ai";
import { discoverAuthStorage } from "@mariozechner/pi-coding-agent";
-
+import { resolveClawdisAgentDir } from "../agents/agent-paths.js";
+import { installSkill } from "../agents/skills-install.js";
+import { buildWorkspaceSkillStatus } from "../agents/skills-status.js";
import {
DEFAULT_AGENT_WORKSPACE_DIR,
ensureAgentWorkspace,
} from "../agents/workspace.js";
-import { resolveClawdisAgentDir } from "../agents/agent-paths.js";
-import { installSkill } from "../agents/skills-install.js";
-import { buildWorkspaceSkillStatus } from "../agents/skills-status.js";
import type { ClawdisConfig } from "../config/config.js";
import {
CONFIG_PATH_CLAWDIS,
@@ -207,7 +206,10 @@ function upsertSkillEntry(
};
}
-function resolveNodeManagerOptions(): Array<{ value: "npm" | "pnpm" | "bun"; label: string }> {
+function resolveNodeManagerOptions(): Array<{
+ value: "npm" | "pnpm" | "bun";
+ label: string;
+}> {
return [
{ value: "npm", label: "npm" },
{ value: "pnpm", label: "pnpm" },
@@ -215,7 +217,10 @@ function resolveNodeManagerOptions(): Array<{ value: "npm" | "pnpm" | "bun"; lab
];
}
-async function moveToTrash(pathname: string, runtime: RuntimeEnv): Promise {
+async function moveToTrash(
+ pathname: string,
+ runtime: RuntimeEnv,
+): Promise {
if (!pathname) return;
try {
await fs.access(pathname);
@@ -382,8 +387,11 @@ export async function onboardCommand(
}
const workspaceDir = resolveUserPath(
- (opts.workspace ?? baseConfig.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR)
- .trim(),
+ (
+ opts.workspace ??
+ baseConfig.agent?.workspace ??
+ DEFAULT_AGENT_WORKSPACE_DIR
+ ).trim(),
);
let nextConfig: ClawdisConfig = {
@@ -513,7 +521,9 @@ export async function onboardCommand(
PATH: process.env.PATH,
CLAWDIS_GATEWAY_TOKEN: gatewayToken,
CLAWDIS_LAUNCHD_LABEL:
- process.platform === "darwin" ? GATEWAY_LAUNCH_AGENT_LABEL : undefined,
+ process.platform === "darwin"
+ ? GATEWAY_LAUNCH_AGENT_LABEL
+ : undefined,
};
await service.install({
env: process.env,
@@ -555,11 +565,15 @@ export async function onboardCommand(
let baseConfig: ClawdisConfig = snapshot.valid ? snapshot.config : {};
if (snapshot.exists) {
- const title = snapshot.valid ? "Existing config detected" : "Invalid config";
+ const title = snapshot.valid
+ ? "Existing config detected"
+ : "Invalid config";
note(summarizeExistingConfig(baseConfig), title);
if (!snapshot.valid && snapshot.issues.length > 0) {
note(
- snapshot.issues.map((iss) => `- ${iss.path}: ${iss.message}`).join("\n"),
+ snapshot.issues
+ .map((iss) => `- ${iss.path}: ${iss.message}`)
+ .join("\n"),
"Config issues",
);
}
@@ -584,8 +598,14 @@ export async function onboardCommand(
message: "Reset scope",
options: [
{ value: "config", label: "Config only" },
- { value: "config+creds+sessions", label: "Config + creds + sessions" },
- { value: "full", label: "Full reset (config + creds + sessions + workspace)" },
+ {
+ value: "config+creds+sessions",
+ label: "Config + creds + sessions",
+ },
+ {
+ value: "full",
+ label: "Full reset (config + creds + sessions + workspace)",
+ },
],
}),
runtime,
@@ -636,7 +656,9 @@ export async function onboardCommand(
runtime,
) as string);
- const workspaceDir = resolveUserPath(workspaceInput.trim() || DEFAULT_AGENT_WORKSPACE_DIR);
+ const workspaceDir = resolveUserPath(
+ workspaceInput.trim() || DEFAULT_AGENT_WORKSPACE_DIR,
+ );
let nextConfig: ClawdisConfig = {
...baseConfig,
@@ -767,7 +789,10 @@ export async function onboardCommand(
}
if (tailscaleMode !== "off" && bind !== "loopback") {
- note("Tailscale requires bind=loopback. Adjusting bind to loopback.", "Note");
+ note(
+ "Tailscale requires bind=loopback. Adjusting bind to loopback.",
+ "Note",
+ );
bind = "loopback";
}
@@ -872,7 +897,10 @@ export async function onboardCommand(
}
}
- if (!loaded || (loaded && (await service.isLoaded({ env: process.env })) === false)) {
+ if (
+ !loaded ||
+ (loaded && (await service.isLoaded({ env: process.env })) === false)
+ ) {
const devMode =
process.argv[1]?.includes(`${path.sep}src${path.sep}`) &&
process.argv[1]?.endsWith(".ts");
@@ -882,7 +910,9 @@ export async function onboardCommand(
PATH: process.env.PATH,
CLAWDIS_GATEWAY_TOKEN: gatewayToken,
CLAWDIS_LAUNCHD_LABEL:
- process.platform === "darwin" ? GATEWAY_LAUNCH_AGENT_LABEL : undefined,
+ process.platform === "darwin"
+ ? GATEWAY_LAUNCH_AGENT_LABEL
+ : undefined,
};
await service.install({
env: process.env,
diff --git a/src/daemon/launchd.ts b/src/daemon/launchd.ts
index 173dde899..257fa7310 100644
--- a/src/daemon/launchd.ts
+++ b/src/daemon/launchd.ts
@@ -25,7 +25,9 @@ export function resolveLaunchAgentPlistPath(
);
}
-export function resolveGatewayLogPaths(env: Record): {
+export function resolveGatewayLogPaths(
+ env: Record,
+): {
logDir: string;
stdoutPath: string;
stderrPath: string;
@@ -160,7 +162,11 @@ async function execLaunchctl(
const { stdout, stderr } = await execFileAsync("launchctl", args, {
encoding: "utf8",
});
- return { stdout: String(stdout ?? ""), stderr: String(stderr ?? ""), code: 0 };
+ return {
+ stdout: String(stdout ?? ""),
+ stderr: String(stderr ?? ""),
+ code: 0,
+ };
} catch (error) {
const e = error as {
stdout?: unknown;
@@ -257,10 +263,16 @@ export async function installLaunchAgent({
await execLaunchctl(["unload", plistPath]);
const boot = await execLaunchctl(["bootstrap", domain, plistPath]);
if (boot.code !== 0) {
- throw new Error(`launchctl bootstrap failed: ${boot.stderr || boot.stdout}`.trim());
+ throw new Error(
+ `launchctl bootstrap failed: ${boot.stderr || boot.stdout}`.trim(),
+ );
}
await execLaunchctl(["enable", `${domain}/${GATEWAY_LAUNCH_AGENT_LABEL}`]);
- await execLaunchctl(["kickstart", "-k", `${domain}/${GATEWAY_LAUNCH_AGENT_LABEL}`]);
+ await execLaunchctl([
+ "kickstart",
+ "-k",
+ `${domain}/${GATEWAY_LAUNCH_AGENT_LABEL}`,
+ ]);
stdout.write(`Installed LaunchAgent: ${plistPath}\n`);
stdout.write(`Logs: ${stdoutPath}\n`);
@@ -276,7 +288,9 @@ export async function restartLaunchAgent({
const label = GATEWAY_LAUNCH_AGENT_LABEL;
const res = await execLaunchctl(["kickstart", "-k", `${domain}/${label}`]);
if (res.code !== 0) {
- throw new Error(`launchctl kickstart failed: ${res.stderr || res.stdout}`.trim());
+ throw new Error(
+ `launchctl kickstart failed: ${res.stderr || res.stdout}`.trim(),
+ );
}
stdout.write(`Restarted LaunchAgent: ${domain}/${label}\n`);
}
diff --git a/src/daemon/program-args.ts b/src/daemon/program-args.ts
index 875601ab1..8e1fcb785 100644
--- a/src/daemon/program-args.ts
+++ b/src/daemon/program-args.ts
@@ -56,7 +56,13 @@ function resolveRepoRootForDev(): string {
}
async function resolveTsxCliPath(repoRoot: string): Promise {
- const candidate = path.join(repoRoot, "node_modules", "tsx", "dist", "cli.mjs");
+ const candidate = path.join(
+ repoRoot,
+ "node_modules",
+ "tsx",
+ "dist",
+ "cli.mjs",
+ );
await fs.access(candidate);
return candidate;
}
diff --git a/src/daemon/schtasks.ts b/src/daemon/schtasks.ts
index a19454dbc..5e1e5da56 100644
--- a/src/daemon/schtasks.ts
+++ b/src/daemon/schtasks.ts
@@ -13,7 +13,9 @@ function resolveHomeDir(env: Record): string {
return home;
}
-function resolveTaskScriptPath(env: Record): string {
+function resolveTaskScriptPath(
+ env: Record,
+): string {
const home = resolveHomeDir(env);
return path.join(home, ".clawdis", "gateway.cmd");
}
@@ -71,7 +73,10 @@ export async function readScheduledTaskCommand(
if (line.toLowerCase().startsWith("rem ")) continue;
if (line.toLowerCase().startsWith("set ")) continue;
if (line.toLowerCase().startsWith("cd /d ")) {
- workingDirectory = line.slice("cd /d ".length).trim().replace(/^"|"$/g, "");
+ workingDirectory = line
+ .slice("cd /d ".length)
+ .trim()
+ .replace(/^"|"$/g, "");
continue;
}
commandLine = line;
@@ -119,7 +124,11 @@ async function execSchtasks(
encoding: "utf8",
windowsHide: true,
});
- return { stdout: String(stdout ?? ""), stderr: String(stderr ?? ""), code: 0 };
+ return {
+ stdout: String(stdout ?? ""),
+ stderr: String(stderr ?? ""),
+ code: 0,
+ };
} catch (error) {
const e = error as {
stdout?: unknown;
@@ -184,7 +193,9 @@ export async function installScheduledTask({
quotedScript,
]);
if (create.code !== 0) {
- throw new Error(`schtasks create failed: ${create.stderr || create.stdout}`.trim());
+ throw new Error(
+ `schtasks create failed: ${create.stderr || create.stdout}`.trim(),
+ );
}
await execSchtasks(["/Run", "/TN", GATEWAY_WINDOWS_TASK_NAME]);
diff --git a/src/daemon/service.ts b/src/daemon/service.ts
index 2ca0eb567..0ce53469e 100644
--- a/src/daemon/service.ts
+++ b/src/daemon/service.ts
@@ -38,10 +38,13 @@ export type GatewayService = {
stdout: NodeJS.WritableStream;
}) => Promise;
restart: (args: { stdout: NodeJS.WritableStream }) => Promise;
- isLoaded: (args: { env: Record }) => Promise;
- readCommand: (
- env: Record,
- ) => Promise<{ programArguments: string[]; workingDirectory?: string } | null>;
+ isLoaded: (args: {
+ env: Record;
+ }) => Promise;
+ readCommand: (env: Record) => Promise<{
+ programArguments: string[];
+ workingDirectory?: string;
+ } | null>;
};
export function resolveGatewayService(): GatewayService {
@@ -102,5 +105,7 @@ export function resolveGatewayService(): GatewayService {
};
}
- throw new Error(`Gateway service install not supported on ${process.platform}`);
+ throw new Error(
+ `Gateway service install not supported on ${process.platform}`,
+ );
}
diff --git a/src/daemon/systemd.ts b/src/daemon/systemd.ts
index e70871f02..d3fb59cee 100644
--- a/src/daemon/systemd.ts
+++ b/src/daemon/systemd.ts
@@ -13,7 +13,9 @@ function resolveHomeDir(env: Record): string {
return home;
}
-function resolveSystemdUnitPath(env: Record): string {
+function resolveSystemdUnitPath(
+ env: Record,
+): string {
const home = resolveHomeDir(env);
return path.join(
home,
@@ -143,7 +145,11 @@ async function execSystemctl(
const { stdout, stderr } = await execFileAsync("systemctl", args, {
encoding: "utf8",
});
- return { stdout: String(stdout ?? ""), stderr: String(stderr ?? ""), code: 0 };
+ return {
+ stdout: String(stdout ?? ""),
+ stderr: String(stderr ?? ""),
+ code: 0,
+ };
} catch (error) {
const e = error as {
stdout?: unknown;
@@ -169,9 +175,13 @@ async function assertSystemdAvailable() {
if (res.code === 0) return;
const detail = res.stderr || res.stdout;
if (detail.toLowerCase().includes("not found")) {
- throw new Error("systemctl not available; systemd user services are required on Linux.");
+ throw new Error(
+ "systemctl not available; systemd user services are required on Linux.",
+ );
}
- throw new Error(`systemctl --user unavailable: ${detail || "unknown error"}`.trim());
+ throw new Error(
+ `systemctl --user unavailable: ${detail || "unknown error"}`.trim(),
+ );
}
export async function installSystemdService({
@@ -191,23 +201,33 @@ export async function installSystemdService({
const unitPath = resolveSystemdUnitPath(env);
await fs.mkdir(path.dirname(unitPath), { recursive: true });
- const unit = buildSystemdUnit({ programArguments, workingDirectory, environment });
+ const unit = buildSystemdUnit({
+ programArguments,
+ workingDirectory,
+ environment,
+ });
await fs.writeFile(unitPath, unit, "utf8");
const unitName = `${GATEWAY_SYSTEMD_SERVICE_NAME}.service`;
const reload = await execSystemctl(["--user", "daemon-reload"]);
if (reload.code !== 0) {
- throw new Error(`systemctl daemon-reload failed: ${reload.stderr || reload.stdout}`.trim());
+ throw new Error(
+ `systemctl daemon-reload failed: ${reload.stderr || reload.stdout}`.trim(),
+ );
}
const enable = await execSystemctl(["--user", "enable", unitName]);
if (enable.code !== 0) {
- throw new Error(`systemctl enable failed: ${enable.stderr || enable.stdout}`.trim());
+ throw new Error(
+ `systemctl enable failed: ${enable.stderr || enable.stdout}`.trim(),
+ );
}
const restart = await execSystemctl(["--user", "restart", unitName]);
if (restart.code !== 0) {
- throw new Error(`systemctl restart failed: ${restart.stderr || restart.stdout}`.trim());
+ throw new Error(
+ `systemctl restart failed: ${restart.stderr || restart.stdout}`.trim(),
+ );
}
stdout.write(`Installed systemd service: ${unitPath}\n`);
@@ -243,7 +263,9 @@ export async function restartSystemdService({
const unitName = `${GATEWAY_SYSTEMD_SERVICE_NAME}.service`;
const res = await execSystemctl(["--user", "restart", unitName]);
if (res.code !== 0) {
- throw new Error(`systemctl restart failed: ${res.stderr || res.stdout}`.trim());
+ throw new Error(
+ `systemctl restart failed: ${res.stderr || res.stdout}`.trim(),
+ );
}
stdout.write(`Restarted systemd service: ${unitName}\n`);
}