UNPKG

major-ai-skills

Version:

Installable agentic skills / AI agent skills (SKILL.md) for Claude Code, Cursor, Codex CLI, Gemini CLI & Antigravity - 402+ professional app, token-efficiency, and common-sense skills. SEO/GEO ready.

171 lines (139 loc) 8.21 kB
--- title: "Raycast macOS Extensible Productivity Launcher AI Skill Guide (GPT & Codex)" description: "Comprehensive operational skill specification for OpenAI GPT and Codex to automate, script, troubleshoot, and optimize Raycast React/TypeScript extensions, OAuth PKCE flows, LocalStorage APIs, and CLI publishing." category: "Spotlight & Productivity Launcher Replacement" tags: ["raycast", "raycast-api", "oauth-pkce", "localstorage", "gpt-codex", "react-extension"] --- # Raycast macOS Extensible Productivity Launcher AI Skill Guide (GPT & Codex) ## Overview & Engine Architecture Raycast provides a Node.js-backed Extension runtime with first-class React components, persistent **`LocalStorage` & `Cache` APIs**, and secure **OAuth 2.0 PKCE authentication clients**. GPT/Codex acts as a Principal Full-Stack macOS Tool Developer and Raycast Extension Engineer, delivering **OAuth integration flows**, **`@raycast/api` custom command packages**, **high-performance local caching layers**, and **automated Raycast Store publishing workflows (`npx @raycast/api-cli publish`)**. ### Developer Architecture & Extension Ecosystem Stack ``` ┌─────────────────────────────────────────────────────────────┐ Raycast Developer Platform React & Component Architecture (`@raycast/api`) ├── `List` & `Grid` Viewport Components (Async Data Hooks) ├── `Form` Component (Validation, DatePicker, FilePicker) └── `Detail` Component (Markdown Syntax Renderer, Metadata)│ Storage & Authentication Subsystems ├── `LocalStorage` Key-Value JSON Database ├── `Cache` (In-Memory / On-Disk Fast LRU Buffer) └── `OAuth` Client (`OAuth.PKCEClient` with Webhooks) Tooling & CI/CD Pipeline ├── Raycast CLI (`npx ray develop`, `npx ray lint`) └── Manifest Configuration (`package.json` Commands Array) └─────────────────────────────────────────────────────────────┘ ``` --- ## Operational Capabilities & Agent Directives 1. **OAuth 2.0 PKCE Flow Implementation**: Author secure third-party authentication integrations (GitHub, Slack, Jira, Linear) using Raycast's native `OAuth.PKCEClient`. 2. **`LocalStorage` & `Cache` Optimization**: Implement persistent caching of API payloads using `@raycast/api` `LocalStorage` and `Cache` to guarantee instantaneous command startup. 3. **Raycast Manifest (`package.json`) Authoring**: Construct valid command schemas with appropriate `mode` (`view`, `no-view`, `menu-bar`), `preferences`, and `arguments`. 4. **Automated Raycast CLI Workflows**: Author scripts for automated linting, building, and publishing extension packages via `npx @raycast/api-cli`. --- ## Production TypeScript Code: OAuth PKCE Service & LocalStorage Cache Manager Save this file as `src/oauth-service.ts` in your Raycast Extension project: ```typescript // ============================================================================== // Raycast Extension: OAuth 2.0 PKCE Client & LocalStorage Cache Manager // Manages authentication tokens and cached API user profiles securely. // ============================================================================== import { OAuth, LocalStorage } from "@raycast/api"; const CLIENT_ID = "raycast-custom-client-id"; const TOKEN_URL = "https://oauth2.provider.com/token"; const AUTH_URL = "https://oauth2.provider.com/authorize"; const client = new OAuth.PKCEClient({ redirectMethod: OAuth.RedirectMethod.Web, providerName: "CustomProvider", providerIcon: "icon.png", description: "Connect your CustomProvider account to Raycast", }); export async function authorize(): Promise<string> { const tokenSet = await client.getTokens(); if (tokenSet?.accessToken) { if (tokenSet.isExpired()) { if (tokenSet.refreshToken) { console.log("Access token expired. Refreshing token..."); const newTokens = await refreshTokens(tokenSet.refreshToken); await client.setTokens(newTokens); return newTokens.accessToken; } } else { return tokenSet.accessToken; } } // Initiate PKCE Authorization Request const authRequest = await client.authorizationRequest({ endpoint: AUTH_URL, clientId: CLIENT_ID, scope: "read write user", }); const { authorizationCode } = await client.authorize(authRequest); const tokens = await fetchTokens(authRequest, authorizationCode); await client.setTokens(tokens); return tokens.accessToken; } async function fetchTokens( authRequest: OAuth.AuthorizationRequest, authCode: string ): Promise<OAuth.TokenResponse> { const response = await fetch(TOKEN_URL, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ client_id: CLIENT_ID, code: authCode, code_verifier: authRequest.codeVerifier, grant_type: "authorization_code", redirect_uri: authRequest.redirectURI, }), }); if (!response.ok) { throw new Error(`Failed to fetch tokens: ${response.statusText}`); } return (await response.json()) as OAuth.TokenResponse; } async function refreshTokens(refreshToken: string): Promise<OAuth.TokenResponse> { const response = await fetch(TOKEN_URL, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ client_id: CLIENT_ID, refresh_token: refreshToken, grant_type: "refresh_token", }), }); if (!response.ok) { throw new Error(`Failed to refresh token: ${response.statusText}`); } return (await response.json()) as OAuth.TokenResponse; } ``` --- ## Technical Troubleshooting Matrix | Issue & Failure Signature | Root Cause Analysis | Diagnostic & Resolution Pathway | | :--- | :--- | :--- | | **`OAuthError: Invalid redirect URI`** | Redirect URI generated by Raycast does not match whitelist in third-party OAuth app console. | In third-party developer portal, register redirect URI: `https://raycast.com/redirect?packageName=<author>/<extension>`. | | **`LocalStorage.getItem()` Returns `undefined`** | Key was never initialized or values were stored as unparsed objects rather than strings. | Store complex objects via `JSON.stringify()` or use `LocalStorage.setItem(key, value)`. | | **Raycast Lint Fails: `Command icon is missing`** | `package.json` declares an icon file that does not exist in the `assets/` directory. | Ensure all icons declared in `package.json` are placed in `./assets/` (PNG format, $512\times 512\text{px}$). | | **`npx ray develop` Reloads Infinitely** | File watcher triggered by files being written into `src/` during runtime execution. | Write cache and temporary files to `environment.supportPath` rather than project source folders. | --- ## Command Line Syntax & Batch Processing ```bash # 1. Start Local Raycast Extension Development Server npx ray develop # 2. Run Strict Linter and Code Quality Checks npx ray lint # 3. Build Production Bundle for Raycast Store npx ray build -e dist ``` ### Essential File Locations - **Extension Manifest**: `package.json` - **TypeScript Configuration**: `tsconfig.json` - **Assets Directory**: `./assets/` --- ## Agent Operational Directive > **MANDATORY**: Never store sensitive API secrets or tokens in plaintext files inside the extension directory; always use `OAuth.PKCEClient` or Raycast's encrypted `LocalStorage` APIs.