Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d42a762
Close Raycast gaps for storage write locking and reset-all backup.
tonythethompson Jul 29, 2026
2db6dca
Fix Raycast write-lock reentrancy and harden reset backup recovery.
cursoragent Jul 29, 2026
6180429
Address CodeRabbit feedback on Raycast storage reset UX.
cursoragent Jul 29, 2026
3b32dfe
Document Raycast reset backup keys and write-queue serialization.
tonythethompson Jul 29, 2026
1e9d985
fix(raycast): add bounded write-lock acquisition timeout
tonythethompson Jul 29, 2026
d36d117
Fix Raycast CmdPal import and unblock transfer file dialogs.
tonythethompson Jul 29, 2026
d75b081
fix(raycast): validate restoreFromBackup shape and do not default mis…
tonythethompson Jul 29, 2026
41fe06e
Restore Raycast focus after import/export file dialogs.
tonythethompson Jul 29, 2026
e005e2f
Address PR 133 review follow-ups for import, restore, and dialogs.
tonythethompson Jul 29, 2026
84b8d8f
Polish Raycast macOS support for Tier A parity.
tonythethompson Jul 29, 2026
05bef39
Update QuickShell.Raycast/src/open-workspace.tsx
tonythethompson Jul 29, 2026
950a287
Update QuickShell.Raycast/src/lib/import-export.ts
tonythethompson Jul 29, 2026
364ecd9
Address Qodo and CodeRabbit review feedback on PR 133.
cursoragent Jul 29, 2026
1c2b479
Block companion launch when the local workspace directory is missing.
cursoragent Jul 29, 2026
99eb966
Fix leftover merge conflict markers and narrow Open Companions catch.
cursoragent Jul 29, 2026
70af5fa
Fix Raycast merge import separators and pwsh dialog fallback.
tonythethompson Jul 29, 2026
5092655
style: fix IDE lint warnings in markdown docs and Raycast source
tonythethompson Jul 29, 2026
d96545b
fix(raycast): toast discover build failures and log macOS dialog errors
cursoragent Jul 29, 2026
153bc6f
Merge branch 'master' into cursor/raycast-storage-reset-and-lock
tonythethompson Jul 29, 2026
ce40516
fix(raycast): prettier-format ReviewWorkspaceForm usePromise destructure
cursoragent Jul 29, 2026
c9fa50d
Address CodeRabbit and Qodo review feedback on PR 133.
tonythethompson Jul 29, 2026
1317fbf
fix(raycast): use terminal toast for no-op reset
tonythethompson Jul 29, 2026
e7383cc
Update AGENTS.md
tonythethompson Jul 29, 2026
ac2d94c
Update QuickShell.Raycast/src/lib/mac-launch.ts
tonythethompson Jul 29, 2026
74a787b
Potential fix for pull request finding 'CodeQL / Useless conditional'
tonythethompson Jul 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ jobs:
run: npm run build

raycast-check-macos:
name: Raycast tests (macOS)
name: Raycast lint, test, and build (macOS)
runs-on: macos-latest
defaults:
run:
Expand All @@ -104,9 +104,18 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Verify Raycast CLI
run: node scripts/verify-raycast-cli.js

- name: Test
run: npm test

- name: Lint
run: npm run lint

- name: Build
run: npm run build

# Informational only: wall-clock medians vary by runner hardware. Never gate PRs on ms budgets.
# Critical-path contracts remain in build-test. Artifacts support manual regression diffs.
perf-harness:
Expand Down
26 changes: 13 additions & 13 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Guidance for coding agents working in QuickShell. Architecture tours live in `do

## Project Overview

Quick Shell is a **Windows-only .NET 10 keyboard-first workspace launcher**. A *workspace* is a saved folder plus metadata (terminal launches, companion app, git target, dev server). The primary surface is a PowerToys Command Palette extension (`QuickShell`), packaged out-of-process as a signed MSIX COM server. Two sibling hosts reuse the same on-disk model: a PowerToys Run plugin (`QuickShell.Run`, `qs` keyword) and a TypeScript Raycast extension (`QuickShell.Raycast`, parallel storage). `QuickShell.Core` owns all domain logic (no CmdPal SDK dependency) so the hosts are swappable UI shells. `QuickShell.Suggest` is a console CLI that emits JSON suggestion pills for Raycast.
Quick Shell's .NET desktop hosts are **Windows-only**; `QuickShell.Raycast` is a separate TypeScript host with macOS support. A _workspace_ is a saved folder plus metadata (terminal launches, companion app, git target, dev server). The primary surface is a PowerToys Command Palette extension (`QuickShell`), packaged out-of-process as a signed MSIX COM server. Two sibling hosts reuse the same on-disk model: a PowerToys Run plugin (`QuickShell.Run`, `qs` keyword) and a TypeScript Raycast extension (`QuickShell.Raycast`, parallel storage). `QuickShell.Core` owns all domain logic (no CmdPal SDK dependency) so the hosts are swappable UI shells. `QuickShell.Suggest` is a console CLI that emits JSON suggestion pills for Raycast.

The UI term is **workspace**; the on-disk file is still `%LOCALAPPDATA%\QuickShell\shortcuts.json`. Keep the product term and the storage term separate in code/comments.

Expand Down Expand Up @@ -36,17 +36,17 @@ The UI term is **workspace**; the on-disk file is still `%LOCALAPPDATA%\QuickShe

## Key Directories

| Path | Purpose |
| ------ | --------- |
| `QuickShell.Core/` | Domain: models, persistence, launch, health, git, terminals, classification, suggestions, companions. **No** CmdPal SDK dependency. `Services/`, `Models/`, `Composition/`, `Classification/`, `Abstractions/`. |
| `QuickShell/` | CmdPal extension: MSIX, Adaptive Card pages, command routing. `Pages/`, `Commands/`, `Services/CommandRouting/`, `Program.cs`, `QuickShell.cs`, `QuickShellCommandsProvider.cs`. |
| `QuickShell.Run/` | PowerToys Run plugin (`IPlugin`, `qs` keyword); consumes Core. |
| `QuickShell.Core.Tests/` | xUnit unit tests for Core (Windows-only TFM). |
| `QuickShell.Raycast/` | Separate npm/TS extension; **not** in the `.sln`; mirrors product rules, shells out to `QuickShell.Suggest`. |
| `QuickShell.Suggest/` | Console CLI emitting JSON suggestion pills for Raycast. |
| `scripts/` | `deploy.ps1`, `run-cmdpal-dev.ps1`, `deploy-all.ps1`/`ddeploy.ps1`, `generate-assets.ps1`, `RaycastLifecycle.ps1`, `build-exe.ps1`, `setup-template.iss`, `LogoAssetGenerator/`. |
| `docs/architecture/` | As-built tours (`overview`, `launch`, `persistence`, `cmdpal-surface`, `hosts`, `settings`, `forms`, `intelligence`, `companions`, `git-and-discover`) + ADRs `0001`-`0005`. |
| `.github/workflows/` | `ci.yml` (build/test), `release-extension.yml` (tag-triggered release + WinGet). |
| Path | Purpose |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `QuickShell.Core/` | Domain: models, persistence, launch, health, git, terminals, classification, suggestions, companions. **No** CmdPal SDK dependency. `Services/`, `Models/`, `Composition/`, `Classification/`, `Abstractions/`. |
| `QuickShell/` | CmdPal extension: MSIX, Adaptive Card pages, command routing. `Pages/`, `Commands/`, `Services/CommandRouting/`, `Program.cs`, `QuickShell.cs`, `QuickShellCommandsProvider.cs`. |
| `QuickShell.Run/` | PowerToys Run plugin (`IPlugin`, `qs` keyword); consumes Core. |
| `QuickShell.Core.Tests/` | xUnit unit tests for Core (Windows-only TFM). |
| `QuickShell.Raycast/` | Separate npm/TS extension; **not** in the `.sln`; mirrors product rules, shells out to `QuickShell.Suggest`. |
| `QuickShell.Suggest/` | Console CLI emitting JSON suggestion pills for Raycast. |
| `scripts/` | `deploy.ps1`, `run-cmdpal-dev.ps1`, `deploy-all.ps1`/`ddeploy.ps1`, `generate-assets.ps1`, `RaycastLifecycle.ps1`, `build-exe.ps1`, `setup-template.iss`, `LogoAssetGenerator/`. |
| `docs/architecture/` | As-built tours (`overview`, `launch`, `persistence`, `cmdpal-surface`, `hosts`, `settings`, `forms`, `intelligence`, `companions`, `git-and-discover`) + ADRs `0001`-`0005`. |
| `.github/workflows/` | `ci.yml` (build/test), `release-extension.yml` (tag-triggered release + WinGet). |

## Development Commands

Expand Down Expand Up @@ -121,7 +121,7 @@ npm run dev # ray develop
## Runtime / Tooling Preferences

- **.NET 10 SDK** (no `global.json`; SDK version implied). Target frameworks differ by project: the `QuickShell` CmdPal host targets `net10.0-windows10.0.26100.0`; `QuickShell.Core`, `QuickShell.Core.Tests`, and `QuickShell.Suggest` target `net10.0-windows7.0`. All are Windows-only (CsWinRT/CsWin32, Windows App SDK, WinUI, MSIX tooling).
- **`QuickShell.Core` has `<UseWindowsForms>true</UseWindowsForms>`** despite owning no CmdPal SDK dependency. It uses WinForms for clipboard/path pickers. So Core is only *compilable* off-Windows (via `-p:EnableWindowsTargeting=true`); it cannot *execute* on Linux. Keep Windows-only APIs in Core minimal so the swappable-host story holds.
- **`QuickShell.Core` has `<UseWindowsForms>true</UseWindowsForms>`** despite owning no CmdPal SDK dependency. It uses WinForms for clipboard/path pickers. So Core is only _compilable_ off-Windows (via `-p:EnableWindowsTargeting=true`); it cannot _execute_ on Linux. Keep Windows-only APIs in Core minimal so the swappable-host story holds.
- **Package manager:** NuGet with **Central Package Management** (`Directory.Packages.props`, `ManagePackageVersionsCentrally=true`). CmdPal SDK is `Microsoft.CommandPalette.Extensions` (NuGet) or a sibling local PowerToys SDK via `-p:UseLocalCmdPalSdk=true` (defines `CMDPAL_HOVER_ACTIONS`; don't assume those APIs exist otherwise).
- **No `.editorconfig` or `global.json`.** Analyzers are on: `EnableNETAnalyzers=true`, `AnalysisMode=Recommended`, plus StyleCop. Treat analyzer warnings seriously; they can break the Windows build.
- **Node >= 22.14** for the Raycast surface; `npm`/`ray` CLI for its build/lint/test.
Expand Down
6 changes: 4 additions & 2 deletions QuickShell.Raycast/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
## [macOS Tier A] - {PR_MERGE_DATE}

- Add macOS to Raycast platforms: Terminal.app / iTerm2 launch, Mac companions, discover roots, import/export dialogs
- Multi-launch on Mac opens separate windows; Windows Terminal tab grouping unchanged on Windows
- Dual-platform keyboard shortcuts; CI macOS test job alongside Windows lint/build
- Multi-launch tabs on Mac (Terminal.app / iTerm2) when the preference is enabled; Windows Terminal tab grouping unchanged on Windows
- Open Directory allows POSIX paths; hide Run as administrator on Mac
- Richer Mac discover roots (`~/Code`, `~/Library/Developer`, Desktop/Documents Projects, …)
- Dual-platform keyboard shortcuts; CI macOS lint/test/build alongside Windows
- Distribution is Raycast Store only (no GitHub Release / WinGet sideload packages)

## [Preferences, useForm, and navigation] - 2026-07-06
Expand Down
6 changes: 3 additions & 3 deletions QuickShell.Raycast/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Raycast-native workspace launcher for Quick Shell on **Windows** and **macOS**.

- **Quick Shell** — search, launch, create, discover git repos, edit, favorite, duplicate, import/export, undo/redo, preferences

**Extension preferences** (Raycast → Extensions → Quick Shell): default terminal app, default profile, show recents, multi-command tabs (Windows), block dirty branch switch.
**Extension preferences** (Raycast → Extensions → Quick Shell): default terminal app, default profile, show recents, multi-command tabs, block dirty branch switch.

Root search: the command is titled **Quick Shell**; its subtitle shows your 3 most recent workspaces. Register it as a fallback command so root-search text seeds the list via `fallbackText`. Open the command and use Actions (Ctrl+K) for Recent / Import / Export. Use **Add to Root Search** on a workspace to create a Quicklink.

Expand All @@ -17,7 +17,7 @@ Create, Discover, and Edit are Actions / pushed views inside Quick Shell (not se
- **Raycast** for Windows or macOS
- **Node.js 22.14+** (development only)
- Windows: Windows Terminal, PowerShell, or WSL
- macOS: Terminal.app and/or iTerm2 (multi-launch opens separate windows)
- macOS: Terminal.app and/or iTerm2 (multi-launch can open as tabs in one window)

## File structure

Expand Down Expand Up @@ -75,4 +75,4 @@ Run `npm run build` before submitting Store changes. Do not add a `version` fiel

Workspaces live in Raycast `LocalStorage` (`quickshell-data`), not shared `%LOCALAPPDATA%\QuickShell\` files. Use **Export Workspaces…** / **Import Workspaces…** (JSON files) to bridge with CmdPal/Run.

Raycast-local parity includes: trust/import contracts, Suggest.exe pills with local fallback (Suggest is Windows-only; Mac uses heuristics), multi-companion form + presets, terminal-host and port-in-use health warnings, copyable launch diagnostics, git launch gate (`branchTargets` + `blockDirtyBranchSwitch`), and layout section separators. Intentional gaps remain: shared LocalAppData stores / Core `worktree-branch-targets.json`, process-list health, ETW, Windows Terminal-style tab grouping on macOS.
Raycast-local parity includes: trust/import contracts, Suggest.exe pills with local fallback (Suggest is Windows-only; Mac uses heuristics), multi-companion form + presets, terminal-host and port-in-use health warnings, copyable launch diagnostics, git launch gate (`branchTargets` + `blockDirtyBranchSwitch`), layout section separators, and multi-launch tabs (Windows Terminal on Windows; Terminal.app / iTerm2 on macOS). Intentional gaps remain: shared LocalAppData stores / Core `worktree-branch-targets.json`, process-list health, ETW, and Suggest CLI on macOS.
4 changes: 2 additions & 2 deletions QuickShell.Raycast/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@
{
"name": "singleWindowTabs",
"title": "Multi-command Launch",
"description": "When supported on Windows, open multiple launch commands as tabs in one Windows Terminal window. On macOS, launches always open as separate windows.",
"description": "Open multiple launch commands as tabs in one window (Windows Terminal on Windows; Terminal.app or iTerm2 on macOS).",
"type": "checkbox",
"required": false,
"default": true,
"label": "Open multiple commands in one Windows Terminal window"
"label": "Open multiple commands as tabs in one window"
},
{
"name": "blockDirtyBranchSwitch",
Expand Down
2 changes: 1 addition & 1 deletion QuickShell.Raycast/raycast-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type ExtensionPreferences = {
"defaultProfile": string,
/** Recent Workspaces - Show recently opened workspaces in Workspaces. */
"showRecents": boolean,
/** Multi-command Launch - When supported on Windows, open multiple launch commands as tabs in one Windows Terminal window. On macOS, launches always open as separate windows. */
/** Multi-command Launch - Open multiple launch commands as tabs in one window (Windows Terminal on Windows; Terminal.app or iTerm2 on macOS). */
"singleWindowTabs": boolean,
/** Git Branch Gate - Block launch when a target branch is set and the working tree has uncommitted changes. */
"blockDirtyBranchSwitch": boolean
Expand Down
10 changes: 8 additions & 2 deletions QuickShell.Raycast/src/__tests__/extension-preferences.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,20 @@ describe("extension-preferences", () => {
expect(windows.multiLaunchPresentation).toBe("separateWindows");
});

it("normalizes Windows terminals to Terminal.app on macOS and forces separate windows", () => {
it("normalizes Windows terminals to Terminal.app on macOS and respects tab preference", () => {
Object.defineProperty(process, "platform", { configurable: true, value: "darwin" });
const settings = preferencesToSettings({
terminalApplication: "wt",
singleWindowTabs: true,
});
expect(settings.terminalApplication).toBe("terminal");
expect(settings.multiLaunchPresentation).toBe("separateWindows");
expect(settings.multiLaunchPresentation).toBe("singleWindowTabs");

const separate = preferencesToSettings({
terminalApplication: "terminal",
singleWindowTabs: false,
});
expect(separate.multiLaunchPresentation).toBe("separateWindows");
});

it("accepts iterm on macOS", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ describe("git-repo-search-roots macOS", () => {
"/Users/dev/Developer",
"/Users/dev/Documents",
"/Users/dev/Documents/GitHub",
"/Users/dev/Code",
"/Users/dev/Sites",
"/Users/dev/GitHub",
"/Users/dev/Library/Developer",
"/Users/dev/Documents/Projects",
"/Users/dev/Desktop/Projects",
"/Users/dev/Desktop/Developer",
]),
);
expect(candidates.some((candidate) => /^[a-zA-Z]:\\/.test(candidate))).toBe(false);
Expand Down
Loading
Loading