--- name: add-ws-action description: Add a new outgoing WebSocket action with typed payload and API exposure aliases: [new-ws-action, add-websocket-action, create-ws-action] --- # Add WebSocket Action Skill ## Usage ``` /add-ws-action ``` --- ## Step 1: Ask Questions ### 1. Action Purpose ``` What does this action do? Brief description: ``` ### 2. Parameters ``` What parameters does the action need? List each with type: - param1: string - param2: number - etc. ``` ### 3. Public API ``` Expose in window.Gemini.WebSocket? A) Yes - Users can call it B) No - Internal only (used by features) ``` ### 4. Middleware ``` Does this action need middleware? A) No - Just send B) Yes - Intercept/modify/block ``` --- ## Step 2: Add Message Type ### In `src/websocket/protocol.ts` ```typescript // 1. Add to enum export enum ClientToServerMessageType { // ... existing = '', } // 2. Define payload type export interface Payload { param1: string; param2: number; } // 3. Add to message map (if exists) export interface ClientToServerMessageMap { // ... existing [ClientToServerMessageType.]: Payload; } ``` --- ## Step 3: Add Action to API ### In `src/websocket/api.ts` ```typescript import { ClientToServerMessageType } from './protocol'; import { send } from './connection'; import type { Payload } from './protocol'; /** * * @param param1 - Description * @param param2 - Description */ export function (param1: string, param2: number): void { send({ type: ClientToServerMessageType., data: { param1, param2 } satisfies Payload, }); } ``` **Keep API simple** - Users pass parameters, not raw payloads. --- ## Step 4: Expose in Public API (if applicable) ### In `src/api/index.ts` ```typescript import { } from '../websocket/api'; WebSocket: { // ... existing , } ``` Accessible via `window.Gemini.WebSocket.(...)`. --- ## Step 5: Optional - Add Middleware ### Create `src/websocket/middlewares/.ts` ```typescript import { registerMiddleware } from './registry'; import { ClientToServerMessageType } from '../protocol'; import type { ClientToServerMessage } from '../protocol'; let unregister: (() => void) | null = null; function processMessage(message: ClientToServerMessage): ClientToServerMessage | null { if (message.type !== ClientToServerMessageType.) { return message; // Pass through } console.log('[] Intercepted:', message.data); // Modify // return { ...message, data: { ...message.data, modified: true } }; // Block // return null; // Pass through return message; } export function registerMiddleware(): void { if (unregister) return; unregister = registerMiddleware(processMessage); } export function unregisterMiddleware(): void { unregister?.(); unregister = null; } ``` --- ## Step 6: Validate ### Protocol - [ ] Message type added to `ClientToServerMessageType` enum - [ ] Payload interface defined - [ ] No hardcoded type strings ### API - [ ] Action function in `src/websocket/api.ts` - [ ] Typed parameters (no `unknown` or `any`) - [ ] Uses `send()` from `connection.ts` - [ ] JSDoc documentation ### Public API (if applicable) - [ ] Exposed in `src/api/index.ts` - [ ] Callable via `window.Gemini.WebSocket.()` ### Middleware (if applicable) - [ ] Returns `message` or `null`, never throws - [ ] Has register/unregister functions - [ ] Unregisters on cleanup --- ## References - Rules: `.claude/rules/websocket/websocket.md` - Existing actions: `src/websocket/api.ts` - Protocol: `src/websocket/protocol.ts` - Middlewares: `src/websocket/middlewares/`