Skip to content

Watchkey: Add Windows support via Windows Hello#26951

Merged
raycastbot merged 2 commits intoraycast:mainfrom
Etheirystech:watchkey/windows-support
Apr 12, 2026
Merged

Watchkey: Add Windows support via Windows Hello#26951
raycastbot merged 2 commits intoraycast:mainfrom
Etheirystech:watchkey/windows-support

Conversation

@Etheirystech
Copy link
Copy Markdown
Contributor

Summary

  • Added cross-platform Windows support using watchkey-win CLI with Windows Hello biometric authentication
  • Platform-aware binary path resolution (macOS: /usr/local/bin, /opt/homebrew/bin; Windows: %LOCALAPPDATA%\watchkey)
  • Fallback to os.homedir() when LOCALAPPDATA env var is unavailable (Raycast sandboxed environment)
  • Update checker and install guard point to the correct platform-specific GitHub repo
  • Import Key command shows "not available" message on Windows (macOS Keychain only)
  • Added "windows" to the platforms array

Test plan

  • On macOS: verify all commands still work as before (no regressions)
  • On Windows: verify install guard detects watchkey-win at %LOCALAPPDATA%\watchkey\watchkey.exe
  • On Windows: verify Get Key, Set Key, Delete Key, Update Key, and List commands work with Windows Hello
  • On Windows: verify Import Key shows "Not Available" message
  • On Windows: verify update check toast points to watchkey-win releases

@raycastbot raycastbot added extension fix / improvement Label for PRs with extension's fix improvements extension: watchkey Issues related to the watchkey extension platform: macOS platform: Windows OP is author The OP of the PR is the author of the extension labels Apr 5, 2026
@raycastbot
Copy link
Copy Markdown
Collaborator

Thank you for the update! 🎉

We're currently experiencing a high volume of incoming requests. As a result, the initial review may take up to 10-15 business days.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 5, 2026

Greptile Summary

This PR adds Windows support to Watchkey using the watchkey-win CLI with Windows Hello biometric authentication, introducing platform-aware path resolution, an update checker, and a 'not available' screen for Import Key on Windows.

  • "windows" in package.json platforms must be "Windows" (capital W) to pass schema validation.
  • import-key.tsx calls useInstallGuard and useUpdateCheck after a conditional early return, violating React's Rules of Hooks.
  • getInstalledVersion() returns the raw CLI string while getLatestVersion() strips the v prefix, so version comparison always mismatches and the update toast fires on every launch.

Confidence Score: 4/5

Do not merge — three P1 issues must be resolved first.

The lowercase 'windows' platform key will fail schema validation, the hooks-after-return pattern violates React rules and will be flagged by ESLint, and the version-string mismatch causes the update toast to fire on every launch.

extensions/watchkey/package.json (platform casing), extensions/watchkey/src/import-key.tsx (hooks order), extensions/watchkey/src/watchkey.ts (version comparison)

Important Files Changed

Filename Overview
extensions/watchkey/CHANGELOG.md Adds Windows support changelog entry with correct {PR_MERGE_DATE} placeholder and descending version order.
extensions/watchkey/package.json Adds Windows platform with incorrect lowercase 'windows' casing (must be 'Windows') and a new update-key command.
extensions/watchkey/src/import-key.tsx Returns early before calling hooks on Windows, violating React Rules of Hooks.
extensions/watchkey/src/install-guard.tsx Platform-aware install guard with correct repo URL and auth method constants; no issues.
extensions/watchkey/src/use-update-check.ts New update-check hook; uses Toast.Style.Failure for an informational notification (minor style concern).
extensions/watchkey/src/watchkey.ts Version comparison between raw CLI output and stripped GitHub tag always mismatches, triggering spurious update toasts on every launch.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/watchkey/package.json
Line: 10

Comment:
**Incorrect `platforms` casing**

The value `"windows"` uses lowercase, but the Raycast schema requires `"Windows"` (capital W). Incorrect casing can cause schema validation failures and block publishing.

```suggestion
    "Windows"
```

**Rule Used:** What: Ensure `platforms` only contains macOS and/o... ([source](https://app.greptile.com/review/custom-context?memory=b3b94d4e-bae6-49ea-b437-ed0f62a1456c))

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/watchkey/src/import-key.tsx
Line: 13-18

Comment:
**React Hooks called after conditional return**

`useInstallGuard` and `useUpdateCheck` are invoked after the early `return` on line 13, violating the Rules of Hooks. ESLint (`react-hooks/rules-of-hooks`) will flag this. Move the platform check after the hook calls:

```suggestion
  const { installed, installView } = useInstallGuard();
  useUpdateCheck();

  if (platform() === "win32") {
    return <Detail markdown="# Not Available\n\nImport Key is only available on macOS. It imports existing macOS Keychain items into watchkey." />;
  }
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/watchkey/src/watchkey.ts
Line: 122-128

Comment:
**Version string mismatch always triggers update toast**

`getInstalledVersion()` returns the raw CLI output (e.g. `"watchkey 1.0.0"` or `"v1.0.0"`), while `getLatestVersion()` strips the `v` prefix via regex, yielding `"1.0.0"`. Because the strings differ in format, `installed !== latest` is always `true` and the update toast fires on every launch. Normalize the installed version:

```suggestion
async function getInstalledVersion(): Promise<string | null> {
  try {
    const output = await execPromise(WATCHKEY_PATH!, ["--version"]);
    const match = output.trim().match(/[\d]+\.[\d]+\.[\d]+(?:[.\-][\w.]+)?/);
    return match ? match[0] : output.trim();
  } catch {
    return null;
  }
}
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "[Watchkey] Add cross-platform Windows su..." | Re-trigger Greptile

Comment thread extensions/watchkey/package.json Outdated
"platforms": [
"macOS"
"macOS",
"windows"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Incorrect platforms casing

The value "windows" uses lowercase, but the Raycast schema requires "Windows" (capital W). Incorrect casing can cause schema validation failures and block publishing.

Suggested change
"windows"
"Windows"

Rule Used: What: Ensure platforms only contains macOS and/o... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/watchkey/package.json
Line: 10

Comment:
**Incorrect `platforms` casing**

The value `"windows"` uses lowercase, but the Raycast schema requires `"Windows"` (capital W). Incorrect casing can cause schema validation failures and block publishing.

```suggestion
    "Windows"
```

**Rule Used:** What: Ensure `platforms` only contains macOS and/o... ([source](https://app.greptile.com/review/custom-context?memory=b3b94d4e-bae6-49ea-b437-ed0f62a1456c))

How can I resolve this? If you propose a fix, please make it concise.

Comment thread extensions/watchkey/src/import-key.tsx Outdated
Comment on lines +13 to +18
if (platform() === "win32") {
return <Detail markdown="# Not Available\n\nImport Key is only available on macOS. It imports existing macOS Keychain items into watchkey." />;
}

const { installed, installView } = useInstallGuard();
useUpdateCheck();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 React Hooks called after conditional return

useInstallGuard and useUpdateCheck are invoked after the early return on line 13, violating the Rules of Hooks. ESLint (react-hooks/rules-of-hooks) will flag this. Move the platform check after the hook calls:

Suggested change
if (platform() === "win32") {
return <Detail markdown="# Not Available\n\nImport Key is only available on macOS. It imports existing macOS Keychain items into watchkey." />;
}
const { installed, installView } = useInstallGuard();
useUpdateCheck();
const { installed, installView } = useInstallGuard();
useUpdateCheck();
if (platform() === "win32") {
return <Detail markdown="# Not Available\n\nImport Key is only available on macOS. It imports existing macOS Keychain items into watchkey." />;
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/watchkey/src/import-key.tsx
Line: 13-18

Comment:
**React Hooks called after conditional return**

`useInstallGuard` and `useUpdateCheck` are invoked after the early `return` on line 13, violating the Rules of Hooks. ESLint (`react-hooks/rules-of-hooks`) will flag this. Move the platform check after the hook calls:

```suggestion
  const { installed, installView } = useInstallGuard();
  useUpdateCheck();

  if (platform() === "win32") {
    return <Detail markdown="# Not Available\n\nImport Key is only available on macOS. It imports existing macOS Keychain items into watchkey." />;
  }
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +122 to +128
async function getInstalledVersion(): Promise<string | null> {
try {
const output = await execPromise(WATCHKEY_PATH!, ["--version"]);
return output.trim();
} catch {
return null;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Version string mismatch always triggers update toast

getInstalledVersion() returns the raw CLI output (e.g. "watchkey 1.0.0" or "v1.0.0"), while getLatestVersion() strips the v prefix via regex, yielding "1.0.0". Because the strings differ in format, installed !== latest is always true and the update toast fires on every launch. Normalize the installed version:

Suggested change
async function getInstalledVersion(): Promise<string | null> {
try {
const output = await execPromise(WATCHKEY_PATH!, ["--version"]);
return output.trim();
} catch {
return null;
}
async function getInstalledVersion(): Promise<string | null> {
try {
const output = await execPromise(WATCHKEY_PATH!, ["--version"]);
const match = output.trim().match(/[\d]+\.[\d]+\.[\d]+(?:[.\-][\w.]+)?/);
return match ? match[0] : output.trim();
} catch {
return null;
}
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/watchkey/src/watchkey.ts
Line: 122-128

Comment:
**Version string mismatch always triggers update toast**

`getInstalledVersion()` returns the raw CLI output (e.g. `"watchkey 1.0.0"` or `"v1.0.0"`), while `getLatestVersion()` strips the `v` prefix via regex, yielding `"1.0.0"`. Because the strings differ in format, `installed !== latest` is always `true` and the update toast fires on every launch. Normalize the installed version:

```suggestion
async function getInstalledVersion(): Promise<string | null> {
  try {
    const output = await execPromise(WATCHKEY_PATH!, ["--version"]);
    const match = output.trim().match(/[\d]+\.[\d]+\.[\d]+(?:[.\-][\w.]+)?/);
    return match ? match[0] : output.trim();
  } catch {
    return null;
  }
}
```

How can I resolve this? If you propose a fix, please make it concise.

Add Windows support via watchkey-win CLI with Windows Hello biometric
authentication. Platform-aware binary path resolution, update checker,
and install instructions. Import Key shows not-available on Windows.
@Etheirystech Etheirystech force-pushed the watchkey/windows-support branch from f3e0506 to 7fa331b Compare April 6, 2026 10:43
@0xdhrv 0xdhrv self-assigned this Apr 12, 2026
Copy link
Copy Markdown
Contributor

@0xdhrv 0xdhrv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, approved ✅

@raycastbot raycastbot merged commit 47e87bd into raycast:main Apr 12, 2026
2 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

Published to the Raycast Store:
https://raycast.com/etheirystech/watchkey

@raycastbot
Copy link
Copy Markdown
Collaborator

🎉 🎉 🎉

We've rewarded your Raycast account with some credits. You will soon be able to exchange them for some swag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extension fix / improvement Label for PRs with extension's fix improvements extension: watchkey Issues related to the watchkey extension OP is author The OP of the PR is the author of the extension platform: macOS platform: Windows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants