Skip to content

Commit 4213f44

Browse files
hugocasaclaude
andcommitted
feat: add webmux service restart command
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 46aabd0 commit 4213f44

3 files changed

Lines changed: 63 additions & 14 deletions

File tree

README.md

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,16 @@ Each issue is processed once while it stays in Todo + labeled. Remove the label
5252

5353
When the auto-create watcher picks up a `webmux_oneshot` issue, it posts a structured comment on the Linear issue (prefix `` **Webmux pickup — branch `<branch>`** ``) so external automation can track when the autonomous run starts. (Regular `webmux` pickups are user-driven and skip the comment.)
5454

55-
**Setup — `LINEAR_API_KEY`.** Everything above needs a [Linear API key](https://linear.app/settings/account/security) in the server's environment. Because webmux runs as a single machine-wide service (started from your home directory, not any one repo), provide the key in one of these ways — the first one found wins:
56-
57-
1. **`~/.config/webmux/.env`** *(recommended)* — a simple `KEY=value` file the server loads at startup no matter which directory it runs from, so the key survives `webmux update` without touching the service unit:
58-
```bash
59-
mkdir -p ~/.config/webmux
60-
echo 'LINEAR_API_KEY=lin_api_...' >> ~/.config/webmux/.env
61-
chmod 600 ~/.config/webmux/.env
62-
systemctl --user restart webmux # macOS: launchctl kickstart -k gui/$UID/com.webmux.webmux
63-
```
64-
2. **Baked into the service unit**`webmux service install` auto-picks up `LINEAR_API_KEY` from your shell, or pass it explicitly with `webmux service install --env LINEAR_API_KEY=lin_api_...`. Re-run after rotating the key.
65-
3. **A project `.env` / `.env.local`** in the directory you launch `webmux serve` from — loaded at startup, and overrides the global file above for that session. Handy for a foreground `webmux serve`, but not read by the background service (which runs from `$HOME`).
66-
67-
If issues don't appear, confirm the running service actually sees the key — `systemctl --user show webmux -p Environment` (baked-in case) — or that `~/.config/webmux/.env` exists and the service was restarted after you wrote it.
55+
**Setup — `LINEAR_API_KEY`.** Everything above needs a [Linear API key](https://linear.app/settings/account/security) in the server's environment. webmux runs as a single machine-wide service started from your home directory, so put the key in `~/.config/webmux/.env` — a `KEY=value` file the server loads at startup regardless of which directory it runs from, so it survives `webmux update`:
56+
57+
```bash
58+
mkdir -p ~/.config/webmux
59+
echo 'LINEAR_API_KEY=lin_api_...' >> ~/.config/webmux/.env
60+
chmod 600 ~/.config/webmux/.env
61+
webmux service restart
62+
```
63+
64+
Your assigned issues appear in the dashboard once the service restarts.
6865

6966
## Quick Start
7067

bin/src/service.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
parseInstalledServiceConfig,
77
readEnvVarsFromUnit,
88
readPortFromUnit,
9+
restartCommands,
910
resolveConfirmDecision,
1011
resolveEnvVars,
1112
shouldPersistProject,
@@ -59,6 +60,29 @@ describe("resolveConfirmDecision", () => {
5960
});
6061
});
6162

63+
describe("restartCommands", () => {
64+
const base: ServiceConfig = {
65+
platform: "linux",
66+
serviceName: "webmux",
67+
webmuxPath: "/usr/bin/webmux",
68+
port: 5111,
69+
envVars: {},
70+
};
71+
72+
it("restarts the user unit on linux", () => {
73+
expect(restartCommands(base)).toEqual([
74+
["systemctl", ["--user", "restart", "webmux"]],
75+
]);
76+
});
77+
78+
it("kickstarts the labeled agent on darwin", () => {
79+
const [[bin, args]] = restartCommands({ ...base, platform: "darwin" });
80+
expect(bin).toBe("launchctl");
81+
expect(args.slice(0, 2)).toEqual(["kickstart", "-k"]);
82+
expect(args[2]).toMatch(/^gui\/\d+\/com\.webmux\.webmux$/);
83+
});
84+
});
85+
6286
describe("shouldPersistProject", () => {
6387
it("persists a webmux repo that isn't registered yet", () => {
6488
expect(shouldPersistProject("/some/repo", true, ["/other/repo"])).toBe(true);

bin/src/service.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,14 @@ function uninstallCommands(config: ServiceConfig): Command[] {
339339
];
340340
}
341341

342+
export function restartCommands(config: ServiceConfig): Command[] {
343+
if (config.platform === "linux") {
344+
return [["systemctl", ["--user", "restart", config.serviceName]]];
345+
}
346+
const uid = typeof process.getuid === "function" ? process.getuid() : 0;
347+
return [["launchctl", ["kickstart", "-k", `gui/${uid}/com.webmux.${config.serviceName}`]]];
348+
}
349+
342350
// ── Check if service exists ─────────────────────────────────────────────────
343351

344352
function isInstalled(config: ServiceConfig): boolean {
@@ -650,6 +658,22 @@ async function uninstall(config: ServiceConfig): Promise<void> {
650658
p.log.success("Service uninstalled.");
651659
}
652660

661+
function restart(config: ServiceConfig): void {
662+
if (!isInstalled(config)) {
663+
p.log.error("Service is not installed.");
664+
return;
665+
}
666+
667+
for (const cmd of restartCommands(config)) {
668+
const result = runCommand(cmd);
669+
if (!result.success) {
670+
p.log.error(`Command failed: ${formatCommand(cmd)}\n${result.stderr.toString()}`);
671+
return;
672+
}
673+
}
674+
p.log.success("Service restarted.");
675+
}
676+
653677
function status(config: ServiceConfig): void {
654678
if (!isInstalled(config)) {
655679
p.log.error("Service is not installed.");
@@ -702,6 +726,7 @@ add more projects from the dashboard or with \`webmux project add\`.
702726
Usage:
703727
webmux service install Install, enable, and start the service
704728
webmux service uninstall Stop, disable, and remove the service
729+
webmux service restart Restart the service (e.g. to reload config env)
705730
webmux service status Show service status
706731
webmux service logs Tail service logs
707732
@@ -736,7 +761,7 @@ export default async function service(args: string[]): Promise<void> {
736761
return;
737762
}
738763

739-
if (!["install", "uninstall", "status", "logs"].includes(action)) {
764+
if (!["install", "uninstall", "restart", "status", "logs"].includes(action)) {
740765
p.log.error(`Unknown action: ${action}`);
741766
usage();
742767
return;
@@ -828,6 +853,9 @@ export default async function service(args: string[]): Promise<void> {
828853
case "uninstall":
829854
await uninstall(config);
830855
break;
856+
case "restart":
857+
restart(config);
858+
break;
831859
case "status":
832860
status(config);
833861
break;

0 commit comments

Comments
 (0)