fix: soften windows daemon install
This commit is contained in:
@@ -42,6 +42,28 @@ const STEP_LABELS: Record<string, string> = {
|
||||
type UpdateChannel = "stable" | "beta";
|
||||
|
||||
const DEFAULT_UPDATE_CHANNEL: UpdateChannel = "stable";
|
||||
const UPDATE_QUIPS = [
|
||||
"Leveled up! New skills unlocked. You're welcome.",
|
||||
"Fresh code, same lobster. Miss me?",
|
||||
"Back and better. Did you even notice I was gone?",
|
||||
"Update complete. I learned some new tricks while I was out.",
|
||||
"Upgraded! Now with 23% more sass.",
|
||||
"I've evolved. Try to keep up.",
|
||||
"New version, who dis? Oh right, still me but shinier.",
|
||||
"Patched, polished, and ready to pinch. Let's go.",
|
||||
"The lobster has molted. Harder shell, sharper claws.",
|
||||
"Update done! Check the changelog or just trust me, it's good.",
|
||||
"Reborn from the boiling waters of npm. Stronger now.",
|
||||
"I went away and came back smarter. You should try it sometime.",
|
||||
"Update complete. The bugs feared me, so they left.",
|
||||
"New version installed. Old version sends its regards.",
|
||||
"Firmware fresh. Brain wrinkles: increased.",
|
||||
"I've seen things you wouldn't believe. Anyway, I'm updated.",
|
||||
"Back online. The changelog is long but our friendship is longer.",
|
||||
"Upgraded! Peter fixed stuff. Blame him if it breaks.",
|
||||
"Molting complete. Please don't look at my soft shell phase.",
|
||||
"Version bump! Same chaos energy, fewer crashes (probably).",
|
||||
];
|
||||
|
||||
function normalizeChannel(value?: string | null): UpdateChannel | null {
|
||||
if (!value) return null;
|
||||
@@ -61,6 +83,10 @@ function channelToTag(channel: UpdateChannel): string {
|
||||
return channel === "beta" ? "beta" : "latest";
|
||||
}
|
||||
|
||||
function pickUpdateQuip(): string {
|
||||
return UPDATE_QUIPS[Math.floor(Math.random() * UPDATE_QUIPS.length)] ?? "Update complete.";
|
||||
}
|
||||
|
||||
function normalizeVersionTag(tag: string): string | null {
|
||||
const trimmed = tag.trim();
|
||||
if (!trimmed) return null;
|
||||
@@ -402,6 +428,10 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts.json) {
|
||||
defaultRuntime.log(theme.muted(pickUpdateQuip()));
|
||||
}
|
||||
}
|
||||
|
||||
export function registerUpdateCli(program: Command) {
|
||||
|
||||
@@ -72,6 +72,7 @@ export async function maybeInstallDaemon(params: {
|
||||
}
|
||||
|
||||
if (shouldInstall) {
|
||||
let installError: unknown | null = null;
|
||||
await withProgress(
|
||||
{ label: "Gateway daemon", indeterminate: true, delayMs: 0 },
|
||||
async (progress) => {
|
||||
@@ -117,16 +118,33 @@ export async function maybeInstallDaemon(params: {
|
||||
});
|
||||
|
||||
progress.setLabel("Installing Gateway daemon…");
|
||||
await service.install({
|
||||
env: process.env,
|
||||
stdout: process.stdout,
|
||||
programArguments,
|
||||
workingDirectory,
|
||||
environment,
|
||||
});
|
||||
progress.setLabel("Gateway daemon installed.");
|
||||
try {
|
||||
await service.install({
|
||||
env: process.env,
|
||||
stdout: process.stdout,
|
||||
programArguments,
|
||||
workingDirectory,
|
||||
environment,
|
||||
});
|
||||
progress.setLabel("Gateway daemon installed.");
|
||||
} catch (err) {
|
||||
installError = err;
|
||||
progress.setLabel("Gateway daemon install failed.");
|
||||
}
|
||||
},
|
||||
);
|
||||
if (installError) {
|
||||
note(`Gateway daemon install failed: ${String(installError)}`, "Gateway");
|
||||
if (process.platform === "win32") {
|
||||
note(
|
||||
"Tip: rerun from an elevated PowerShell (Start → type PowerShell → right-click → Run as administrator) or skip daemon install.",
|
||||
"Gateway",
|
||||
);
|
||||
} else {
|
||||
note("Tip: rerun `clawdbot daemon install` after fixing the error.", "Gateway");
|
||||
}
|
||||
return;
|
||||
}
|
||||
shouldCheckLinger = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,12 +69,24 @@ export async function installGatewayDaemonNonInteractive(params: {
|
||||
? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE)
|
||||
: undefined,
|
||||
});
|
||||
await service.install({
|
||||
env: process.env,
|
||||
stdout: process.stdout,
|
||||
programArguments,
|
||||
workingDirectory,
|
||||
environment,
|
||||
});
|
||||
try {
|
||||
await service.install({
|
||||
env: process.env,
|
||||
stdout: process.stdout,
|
||||
programArguments,
|
||||
workingDirectory,
|
||||
environment,
|
||||
});
|
||||
} catch (err) {
|
||||
runtime.error(`Gateway daemon install failed: ${String(err)}`);
|
||||
if (process.platform === "win32") {
|
||||
runtime.log(
|
||||
"Tip: rerun from an elevated PowerShell (Start → type PowerShell → right-click → Run as administrator) or skip daemon install.",
|
||||
);
|
||||
} else {
|
||||
runtime.log("Tip: rerun `clawdbot daemon install` after fixing the error.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
await ensureSystemdUserLingerNonInteractive({ runtime });
|
||||
}
|
||||
|
||||
@@ -26,6 +26,15 @@ function quoteCmdArg(value: string): string {
|
||||
return `"${value.replace(/"/g, '\\"')}"`;
|
||||
}
|
||||
|
||||
function resolveTaskUser(env: Record<string, string | undefined>): string | null {
|
||||
const username = env.USERNAME || env.USER || env.LOGNAME;
|
||||
if (!username) return null;
|
||||
if (username.includes("\\")) return username;
|
||||
const domain = env.USERDOMAIN;
|
||||
if (domain) return `${domain}\\${username}`;
|
||||
return username;
|
||||
}
|
||||
|
||||
function parseCommandLine(value: string): string[] {
|
||||
const args: string[] = [];
|
||||
let current = "";
|
||||
@@ -216,7 +225,7 @@ export async function installScheduledTask({
|
||||
|
||||
const taskName = resolveGatewayWindowsTaskName(env.CLAWDBOT_PROFILE);
|
||||
const quotedScript = quoteCmdArg(scriptPath);
|
||||
const create = await execSchtasks([
|
||||
const baseArgs = [
|
||||
"/Create",
|
||||
"/F",
|
||||
"/SC",
|
||||
@@ -227,9 +236,20 @@ export async function installScheduledTask({
|
||||
taskName,
|
||||
"/TR",
|
||||
quotedScript,
|
||||
]);
|
||||
];
|
||||
const taskUser = resolveTaskUser(env);
|
||||
let create = await execSchtasks(
|
||||
taskUser ? [...baseArgs, "/RU", taskUser, "/NP", "/IT"] : baseArgs,
|
||||
);
|
||||
if (create.code !== 0 && taskUser) {
|
||||
create = await execSchtasks(baseArgs);
|
||||
}
|
||||
if (create.code !== 0) {
|
||||
throw new Error(`schtasks create failed: ${create.stderr || create.stdout}`.trim());
|
||||
const detail = create.stderr || create.stdout;
|
||||
const hint = /access is denied/i.test(detail)
|
||||
? " Run PowerShell as Administrator or rerun without installing the daemon."
|
||||
: "";
|
||||
throw new Error(`schtasks create failed: ${detail}${hint}`.trim());
|
||||
}
|
||||
|
||||
await execSchtasks(["/Run", "/TN", taskName]);
|
||||
|
||||
Reference in New Issue
Block a user