Files
caffeinate-extension/package.json
T
adrianbonpin 65005b22a6 Add native Vicinae caffeinate extension
Keeps the computer awake from Vicinae. Written against @vicinae/api
directly because the Raycast `coffee` extension cannot work here:

- Its `index` command is `menu-bar` mode, which Vicinae does not support.
- Its `status` command crashes on `Cannot read properties of null
  (reading 'IsManuallyDecafed')` because it gates on
  `LocalStorage.getItem(key) === undefined`. Vicinae resolves a missing
  key to `null`, not `undefined` (verified with a runtime probe).

Sleep prevention is an OS-level assertion, so the extension delegates and
gets out of the way:

- macOS:  caffeinate -i [-d] [-s] [-t <seconds>]
- Linux:  systemd-inhibit --what=idle:sleep --why=<reason> sleep <n|infinity>

The process is spawned detached + unref'd, because Vicinae unloads a
no-view command as soon as its function returns. Timed sessions need no
babysitter: `caffeinate -t` and `sleep <n>` self-terminate.

Commands: toggle (no-view), status (view), caffeinate-for (view).

Two deliberate safety choices:
- Stopping signals the recorded PID rather than running `killall
  caffeinate`, so a caffeinate the user started themselves survives.
  Verified against a real concurrent `caffeinate -u -dmi` process.
- The PID's name is re-checked with `ps -o comm=` before signalling, since
  PIDs get recycled and a stale entry could otherwise kill something
  unrelated.

Also: display-sleep prevention is macOS-only, and the UI says so on Linux
rather than pretending systemd-inhibit can hold the display awake.

Verified: vici lint, tsc --noEmit, eslint, 23/23 vitest, vici build, and
live in Vicinae — toggle starts `caffeinate -i` which survives the
command unloading, toggle again stops only ours, both view commands load
with clean stdout/stderr.
2026-09-20 16:16:57 +08:00

78 lines
2.3 KiB
JSON

{
"$schema": "https://raw.githubusercontent.com/vicinaehq/vicinae/refs/heads/main/extra/schemas/extension.json",
"name": "caffeinate",
"title": "Caffeinate",
"description": "Keep your computer awake. Start, stop, and time-limit sleep prevention without touching a terminal.",
"icon": "caffeinate.png",
"author": "adrianbonpin",
"categories": [
"System"
],
"license": "MIT",
"commands": [
{
"name": "toggle",
"title": "Toggle Caffeination",
"description": "Start or stop keeping your computer awake, depending on the current state.",
"mode": "no-view"
},
{
"name": "status",
"title": "Caffeination Status",
"description": "See whether sleep is currently being prevented, and for how much longer. Start or stop it from here.",
"mode": "view"
},
{
"name": "caffeinate-for",
"title": "Caffeinate for a Duration",
"description": "Keep your computer awake for a set amount of time, then let it sleep again automatically.",
"mode": "view"
}
],
"preferences": [
{
"name": "preventDisplaySleep",
"title": "Also Prevent Display Sleep",
"description": "Keep the screen on as well. Off means the display may still turn off while the system stays awake.",
"type": "checkbox",
"label": "Prevent display sleep",
"required": false,
"default": false
},
{
"name": "preventSystemSleep",
"title": "Also Prevent System Sleep",
"description": "Prevents full system sleep. Note: on macOS this assertion only takes effect while on AC power.",
"type": "checkbox",
"label": "Prevent system sleep",
"required": false,
"default": false
}
],
"dependencies": {
"@vicinae/api": "^0.29.0"
},
"devDependencies": {
"@eslint/js": "^9.36.0",
"@types/node": "22.13.10",
"@types/react": "19.1.17",
"eslint": "^9.22.0",
"eslint-config-prettier": "^10.1.8",
"globals": "^16.4.0",
"prettier": "^3.5.3",
"react": "19.1.1",
"typescript": "^5.8.2",
"typescript-eslint": "^8.45.0",
"vitest": "^4.1.5"
},
"scripts": {
"dev": "vici develop",
"build": "vici build",
"lint": "vici lint",
"lint:code": "eslint .",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest"
}
}