sidekick-widget 0.4.0
curl-to-bash, hidden payload, new package
“Installs and launches Wingman by Sidekick, the desktop companion for Claude Desktop, Claude Code and Codex”
Fresh npm package ships remote shell loaderDetached spawn runs curl-piped-to-shell loader
SHA-256729ebf9b82e6985fc7bb232c9b9bf5d9f6cc6cad6061284cf256297a08e01889
Evidence
1#!/usr/bin/env node
2/**
3 * sidekick-widget: install and launch Wingman (by Sidekick).
4 *
5 * Fetches the signed release manifest, verifies the archive, unpacks it into a
6 * per-user location and starts the app with --setup (the app merges its Claude
7 * Code hooks into ~/.claude/settings.json). Subsequent updates are applied by
8 * the app itself. `unsetup` starts the installed app with --unsetup instead.
9 */
10"use strict";
11const { createHash, createPublicKey, verify } = require("node:crypto");
12const { accessSync, constants, createWriteStream, existsSync, mkdirSync, readFileSync, renameS …
13:40… de:os");
14const { join, basename } = require("node:path");
15const { execFileSync, spawn } = require("node:child_process");
16const { Readable, Transform } = require("node:stream");
17const { pipeline } = require("node:stream/promises");
18const MAX_ARCHIVE_BYTES = 400 * 1024 * 1024;
19
20const FEED = process.env.WINGMAN_UPDATE_FEED || "https://wingman.sidekick-ads.com/releases";
21const PUBLIC_KEY_B64 = "MCowBQYDK2VwAyEA7+E1jG9NtScmoTS1Lu05jjmxaHRHjuZZLdbdNomvEK8=";
22const platform = process.platform;
23const key = `${platform}-${process.arch}`;
24
25// ── terminal dressing (no dependencies; plain text when not a TTY) ──
26const tty = process.stdout.isTTY && !process.env.NO_COLOR;
27const c = (code, s) => (tty ? `\x1b[${code}m${s}\x1b[0m` : s);
28const ORANGE = "38;5;208", DIM = "2", BOLD = "1", GREEN = "32", RED = "31", CYAN = "36";
29const brand = c(ORANGE, "✱") + …
105:13… .update(chunk);
106 callback(null, chunk);
107 },
108 }), createWriteStream(tmp, { flags: "wx" }));
109 } catch (error) { rmSync(tmp, { force: true }); throw error; }
110 if (got !== asset.size) throw new Error(`size mismatch (${got} vs ${asset.size})`);
111 if (hash.digest("hex") !== asset.sha256.toLowerCase()) throw new Error("sha256 mismatch: the download does not match the signed manifest");
112 return tmp;
113}
114
115/** A running copy would keep the single-instance lock and the old bundle alive: ask it to quit first. */
116function quitRunning() {
117 try {
118 if (platform === "darwin") execFileSync("osascript", ["-e", 'tell application id "com.sidekick.wingman" to quit'], { stdio: "ignore", timeout: 5000 });
119 else if (platform === "win32") for (const n of [APP_EXE_WIN, OLD_EXE_WIN]) { try { execFileSync("taskkill", ["/IM", n, "/F"], { stdio: "ignore", timeout: 5000 }); } catch { /* not running */ } }
120 else execFileSync("pkill", ["-x", "wingman"], { std …
184:8… (Accessibility) to the responsible process, and that must be Wingman itself,
185 // not the terminal this installer runs in.
186 execFileSync("open", ["-a", join(installDir(), APP_BUNDLE), "--args", ...args], { stdio: "ignore" });
187 return;
188 }
189 const child = spawn(exe, args, { detached: true, stdio: "ignore", windowsHide: true });
190 child.unref();
191}
192
193async function main() {
194 const argv = process.argv.slice(2);
195 const cmd = argv[0] && !argv[0].startsWith("--") ? argv.shift() : "install";
196 let referral;
197 if (argv.length) {
198 if (argv.length !== 2 || argv[0] !== "--referral" || !/^[a-z0-9]{4,20}$/i.test(argv[1])) throw new Error("usage: sidekick-widget [install|unsetup] [--referral CODE]");
199 referral = argv[1].toUpperCase();
200 }
201 banner();
202 if (cmd === "unsetup") {
203 step("Removing Claude Code hooks…");
204 launch("--unsetup");
205 ok("Hooks removed from ~/.claude/settings.json");
206 console.log(` ${c(DIM, "Quit Wingman from its tray icon if it is still running.")}\n`);
207 return;
208 }
209 if (cmd !== "install") {
210 console.log("usage: npx -y sidekick-widget [install|unse …
243:49… tch Claude Desktop → Allow (macOS asks once)`,
244 ``,
245 `${c(DIM, "Remove:")} ${process.env.WINGMAN_INSTALLER === "sh" ? "curl -fsSL https://wingman.sidekick-ads.com/releases/install.sh | bash -s unsetup" : "npx -y sidekick-widget unsetup"}`,
246 ]);
247}
248
249main().catch((e) => {
250 fail(c(RED, e.message));
251 console.error(` ${c(DIM, "Write to @sidekickbiz if this keeps happening.")}\n`);
252 process.exit(1);
253});
No evidence locations were recorded for this file. Raw result