From 662854ee1c5e4f26d3291a643f535ebe4cba5d98 Mon Sep 17 00:00:00 2001 From: ryoppippi <1560508+ryoppippi@users.noreply.github.com> Date: Tue, 9 Dec 2025 13:36:15 +0000 Subject: [PATCH] refactor(skills): unify cursor rules and claude skills Replace separate Cursor rules with symlinks to Claude skills, making skills the single source of truth for both AI tools. Changes: - Add globs/alwaysApply fields to SKILL.md for Cursor compatibility - Improve skill descriptions to clarify when each should be used - Replace .cursor/rules/*.mdc files with symlinks to .claude/skills/ - Add PR title guidelines to development-workflow skill - Consolidate clean-code patterns into typescript-patterns skill - Simplify CLAUDE.md to reference unified skill structure This eliminates content duplication and ensures consistent guidance across Cursor and Claude Code. Fixes #156 --- .claude/skills/development-workflow/SKILL.md | 28 ++- .claude/skills/file-operations/SKILL.md | 4 +- .claude/skills/orama-integration/SKILL.md | 4 +- .claude/skills/typescript-patterns/SKILL.md | 28 ++- .claude/skills/typescript-testing/SKILL.md | 4 +- .cursor/rules/clean-code.mdc | 119 --------- .cursor/rules/cursor-rules-location.mdc | 75 ------ .cursor/rules/development-workflow.mdc | 1 + .cursor/rules/examples-standards.mdc | 112 --------- .cursor/rules/file-operations.mdc | 1 + .cursor/rules/file-utils.mdc | 111 -------- .cursor/rules/json-schema-handling.mdc | 110 -------- .cursor/rules/native-fetch.mdc | 128 ---------- .cursor/rules/orama-integration.mdc | 1 + .cursor/rules/pnpm-standards.mdc | 48 ---- .cursor/rules/release-please-standards.mdc | 77 ------ .cursor/rules/typescript-best-practices.mdc | 168 ------------- .cursor/rules/typescript-patterns.mdc | 1 + .cursor/rules/typescript-testing.mdc | 1 + .cursor/rules/vitest-mocks.mdc | 250 ------------------- CLAUDE.md | 71 +----- 21 files changed, 69 insertions(+), 1273 deletions(-) delete mode 100644 .cursor/rules/clean-code.mdc delete mode 100644 .cursor/rules/cursor-rules-location.mdc create mode 120000 .cursor/rules/development-workflow.mdc delete mode 100644 .cursor/rules/examples-standards.mdc create mode 120000 .cursor/rules/file-operations.mdc delete mode 100644 .cursor/rules/file-utils.mdc delete mode 100644 .cursor/rules/json-schema-handling.mdc delete mode 100644 .cursor/rules/native-fetch.mdc create mode 120000 .cursor/rules/orama-integration.mdc delete mode 100644 .cursor/rules/pnpm-standards.mdc delete mode 100644 .cursor/rules/release-please-standards.mdc delete mode 100644 .cursor/rules/typescript-best-practices.mdc create mode 120000 .cursor/rules/typescript-patterns.mdc create mode 120000 .cursor/rules/typescript-testing.mdc delete mode 100644 .cursor/rules/vitest-mocks.mdc diff --git a/.claude/skills/development-workflow/SKILL.md b/.claude/skills/development-workflow/SKILL.md index 30c4eaf7..39c9e485 100644 --- a/.claude/skills/development-workflow/SKILL.md +++ b/.claude/skills/development-workflow/SKILL.md @@ -1,6 +1,8 @@ --- name: development-workflow -description: Build, development, and code quality commands for StackOne SDK +description: Build commands, testing, linting, git workflow, commit conventions, and file naming standards. (project) +globs: "" +alwaysApply: true --- # Development Workflow @@ -107,7 +109,29 @@ feat(parser): add support for custom parameter transformers 4. Verify with `git status` before committing ### TypeScript Issues -Use the TypeScript exhaustiveness pattern (`satisfies never`) when branching on unions. See `openapi-architecture` skill for examples. +Use the TypeScript exhaustiveness pattern (`satisfies never`) when branching on unions. See `typescript-patterns` skill for examples. + +## Pull Request Guidelines + +### PR Title Format +Use the same format as commit messages: `type(scope): description` + +Types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `ci`, `perf` + +Examples: +- `feat(tools): add support for custom OpenAPI specs` +- `fix(parser): handle empty response bodies` +- `refactor(skills): unify cursor rules and claude skills` + +### PR Body +Include: +- **Summary**: 1-3 bullet points describing changes +- **Test plan**: How to verify the changes work +- Reference related issues with `Closes #123` or `Fixes #123` + +## File Naming Conventions + +- Use `.yaml` extension instead of `.yml` for all YAML files (e.g., `lefthook.yaml`, GitHub Actions workflows) ## Working with Tools diff --git a/.claude/skills/file-operations/SKILL.md b/.claude/skills/file-operations/SKILL.md index 587b160d..4b36ccce 100644 --- a/.claude/skills/file-operations/SKILL.md +++ b/.claude/skills/file-operations/SKILL.md @@ -1,6 +1,8 @@ --- name: file-operations -description: File operations and HTTP request standards for StackOne SDK +description: Use when working with files or HTTP requests. Covers src/utils/file.ts utilities, native fetch API patterns. (project) +globs: "*.ts" +alwaysApply: false --- # File Operations and HTTP Standards diff --git a/.claude/skills/orama-integration/SKILL.md b/.claude/skills/orama-integration/SKILL.md index 52f2d33e..519170ea 100644 --- a/.claude/skills/orama-integration/SKILL.md +++ b/.claude/skills/orama-integration/SKILL.md @@ -1,6 +1,8 @@ --- name: orama-integration -description: Orama API integration reference for StackOne +description: Use when integrating with Orama. Links to official docs for search, indexing, answer engine. (project) +globs: "" +alwaysApply: false --- # Orama Integration diff --git a/.claude/skills/typescript-patterns/SKILL.md b/.claude/skills/typescript-patterns/SKILL.md index 40465f4d..8d512129 100644 --- a/.claude/skills/typescript-patterns/SKILL.md +++ b/.claude/skills/typescript-patterns/SKILL.md @@ -1,11 +1,13 @@ --- name: typescript-patterns -description: TypeScript patterns and best practices for StackOne SDK +description: Use when writing or reviewing TypeScript code. Covers type safety, exhaustiveness checks, avoiding any/non-null assertions, clean code practices. (project) +globs: "*.ts" +alwaysApply: false --- # TypeScript Patterns and Best Practices -This skill provides guidance on TypeScript patterns and best practices for writing clean, type-safe code in the StackOne SDK. +Guidelines for writing clean, type-safe TypeScript code in this repository. ## Exhaustiveness Checking with `satisfies never` @@ -207,12 +209,20 @@ function removeProperty(obj: Record): void { } ``` -## Recommendations +## Remove Unused Code -1. Use `satisfies never` for all union type switches -2. Prefer `unknown` over `any` and use type guards -3. Use optional chaining (`?.`) and nullish coalescing (`??`) +After refactoring, always remove unused code: +- Delete unused variables, parameters, functions, classes, imports +- Don't comment out old code - delete it (git history preserves it) +- Remove unreachable code paths + +## Quick Reference + +1. Use `satisfies never` for union type switches +2. Prefer `unknown` over `any` with type guards +3. Use `?.` and `??` instead of non-null assertions 4. Always specify return types -5. Use destructuring for immutable property removal -6. Write functions as simple exports, not class static methods -7. Create new variables instead of reassigning parameters +5. Use destructuring for property removal +6. Use simple exports instead of static-only classes +7. Don't reassign parameters - create new variables +8. Remove unused code after refactoring diff --git a/.claude/skills/typescript-testing/SKILL.md b/.claude/skills/typescript-testing/SKILL.md index d2cec3d3..6e8e13d2 100644 --- a/.claude/skills/typescript-testing/SKILL.md +++ b/.claude/skills/typescript-testing/SKILL.md @@ -1,6 +1,8 @@ --- name: typescript-testing -description: Vitest test runner and MSW-based testing patterns for StackOne SDK +description: Use when writing or running tests. Covers Vitest commands, MSW HTTP mocking, fs-fixture for file system tests. (project) +globs: "*.spec.ts" +alwaysApply: false --- # TypeScript Testing with Vitest and MSW diff --git a/.cursor/rules/clean-code.mdc b/.cursor/rules/clean-code.mdc deleted file mode 100644 index 456741ce..00000000 --- a/.cursor/rules/clean-code.mdc +++ /dev/null @@ -1,119 +0,0 @@ ---- -description: Standards for maintaining clean, readable, and maintainable code in the repository. -globs: src/**/*.ts -alwaysApply: false ---- -# Clean Code Standards - -Standards for maintaining clean, readable, and maintainable code in the repository. - - -name: remove_unused_code -description: Always remove unused code after refactoring to maintain a clean codebase - -filters: - - type: path - pattern: "^src/.*\\.ts$" - -actions: - - type: suggest - message: | - After refactoring, always remove unused code to maintain a clean and maintainable codebase: - - 1. Remove unused: - - Variables, parameters, and function arguments - - Functions, methods, and classes - - Imports and exports - - Properties in interfaces and types - - Commented-out code blocks - - 2. Benefits of removing unused code: - - Reduces cognitive load when reading code - - Prevents confusion about which code paths are actually used - - Improves maintainability by reducing the surface area of the codebase - - Makes the codebase easier to understand for new contributors - - Prevents "dead" code from being accidentally reactivated - - 3. Tools to help identify unused code: - - TypeScript compiler with `noUnusedLocals` and `noUnusedParameters` flags - - ESLint with rules like `no-unused-vars` and `no-dead-code` - - IDE features that gray out unused code - - Code coverage tools to identify untested (potentially unused) code paths - - 4. When refactoring: - - Don't comment out old code - delete it (git history preserves it) - - Remove any code paths that are no longer reachable - - Delete any functions that are no longer called - - Remove any parameters that are no longer used - - Clean up imports that are no longer needed - -examples: - - input: | - import { parseJson, formatJson, validateJson } from './utils'; - - function processData(data: string, options: { validate: boolean }): object { - // Old implementation - // const parsed = JSON.parse(data); - // return parsed; - - const parsed = parseJson(data); - - // We might need validation later - // if (options.validate) { - // validateJson(parsed); - // } - - return parsed; - } - output: | - import { parseJson } from './utils'; - - function processData(data: string): object { - const parsed = parseJson(data); - return parsed; - } - - - input: | - class DataProcessor { - private cache: Map = new Map(); - private logger: Logger; - private config: Config; - - constructor(logger: Logger, config: Config) { - this.logger = logger; - this.config = config; - } - - process(data: string): object { - const result = JSON.parse(data); - return result; - } - - // Old method, no longer used after refactoring - // cacheResult(key: string, data: any): void { - // this.cache.set(key, data); - // this.logger.debug(`Cached data for key: ${key}`); - // } - } - output: | - class DataProcessor { - private logger: Logger; - - constructor(logger: Logger) { - this.logger = logger; - } - - process(data: string): object { - const result = JSON.parse(data); - return result; - } - } - -metadata: - priority: high - version: 1.0 - tags: - - clean-code - - refactoring - - best-practices - \ No newline at end of file diff --git a/.cursor/rules/cursor-rules-location.mdc b/.cursor/rules/cursor-rules-location.mdc deleted file mode 100644 index 4d1bd9f7..00000000 --- a/.cursor/rules/cursor-rules-location.mdc +++ /dev/null @@ -1,75 +0,0 @@ ---- -description: Standards for placing Cursor rule files in the correct -globs: *.mdc ---- -# Cursor Rules Location - -Rules for placing and organizing Cursor rule files in the repository. - - -name: cursor_rules_location -description: Standards for placing Cursor rule files in the correct directory -filters: - # Match any .mdc files - - type: file_extension - pattern: "\\.mdc$" - # Match files that look like Cursor rules - - type: content - pattern: "(?s).*?" - # Match file creation events - - type: event - pattern: "file_create" - -actions: - - type: reject - conditions: - - pattern: "^(?!\\.\\/\\.cursor\\/rules\\/.*\\.mdc$)" - message: "Cursor rule files (.mdc) must be placed in the .cursor/rules directory" - - - type: suggest - message: | - When creating Cursor rules: - - 1. Always place rule files in PROJECT_ROOT/.cursor/rules/: - ``` - .cursor/rules/ - ├── your-rule-name.mdc - ├── another-rule.mdc - └── ... - ``` - - 2. Follow the naming convention: - - Use kebab-case for filenames - - Always use .mdc extension - - Make names descriptive of the rule's purpose - - 3. Directory structure: - ``` - PROJECT_ROOT/ - ├── .cursor/ - │ └── rules/ - │ ├── your-rule-name.mdc - │ └── ... - └── ... - ``` - - 4. Never place rule files: - - In the project root - - In subdirectories outside .cursor/rules - - In any other location - -examples: - - input: | - # Bad: Rule file in wrong location - rules/my-rule.mdc - my-rule.mdc - .rules/my-rule.mdc - - # Good: Rule file in correct location - .cursor/rules/my-rule.mdc - output: "Correctly placed Cursor rule file" - -metadata: - priority: high - version: 1.0 - \ No newline at end of file diff --git a/.cursor/rules/development-workflow.mdc b/.cursor/rules/development-workflow.mdc new file mode 120000 index 00000000..ae7c011d --- /dev/null +++ b/.cursor/rules/development-workflow.mdc @@ -0,0 +1 @@ +../../.claude/skills/development-workflow/SKILL.md \ No newline at end of file diff --git a/.cursor/rules/examples-standards.mdc b/.cursor/rules/examples-standards.mdc deleted file mode 100644 index 20ede611..00000000 --- a/.cursor/rules/examples-standards.mdc +++ /dev/null @@ -1,112 +0,0 @@ ---- -description: Standards for creating and maintaining examples in the StackOne repository -globs: examples/* -alwaysApply: false ---- -# Examples Standards - -Standards for creating and maintaining examples in the StackOne repository. - - -name: examples_standards -description: Standards for creating and maintaining examples for all functionality - -filters: - - type: path - pattern: "^examples/.*" - -actions: - - type: suggest - message: | - When working with examples: - - 1. Location Requirements: - ``` - examples/ - ├── basic_usage/ - │ ├── basic_tool_usage.ts # Basic usage examples - │ └── error_handling.ts # Error handling examples - ├── integrations/ # Integration examples - │ ├── openai_integration.ts - │ └── other_integration.ts - └── README.md # Examples documentation - ``` - - 2. Example Requirements: - - Every public function/class needs at least one example - - Examples should be runnable TypeScript scripts - - Use Node's assert module for validation instead of console.logs - - Include proper error handling with try/catch blocks - - Include TypeScript return types for all functions - - Follow the same code style as the main codebase - - Exit with non-zero code on error using process.exit(1) - - 3. Documentation: - - Each example file should start with a docstring explaining its purpose - - Use assertions to validate expected behavior - - Document any prerequisites (environment variables, etc) - - 4. Testing: - - Examples should be tested as part of CI - - Examples should work with the latest package version - - Use assertions to verify expected behavior - -examples: - - input: | - /** - * Example showing basic usage of StackOneToolSet. - */ - - import assert from 'node:assert'; - import { StackOneToolSet } from '../src'; - - const exampleFunction = async (): Promise => { - // Initialize the toolset - const toolset = new StackOneToolSet(); - - // Get tools and verify - const tools = toolset.getTools('hris_*'); - assert(tools.length > 0, 'Expected to find HRIS tools'); - - // Use a specific tool - const employeeTool = tools.getTool('hris_list_employees'); - assert(employeeTool !== undefined, 'Expected to find tool'); - - // Execute and verify result - const result = await employeeTool.execute(); - assert(Array.isArray(result), 'Expected result to be an array'); - }; - - // Run the example - exampleFunction().catch((error) => { - console.error('Error:', error); - process.exit(1); - }); - output: "Correctly structured example" - - - input: | - // Bad example - missing assertions, error handling, types - import { StackOneToolSet } from '../src'; - - const badExample = async () => { - const toolset = new StackOneToolSet(); - const tools = toolset.getTools("hris_*"); - const tool = tools.getTool("hris_list_employees"); - - if (tool) { - const result = await tool.execute(); - console.log(result); - } - }; - - badExample(); - output: "Incorrectly structured example" - -metadata: - priority: high - version: 1.0 - tags: - - examples - - documentation - - testing - \ No newline at end of file diff --git a/.cursor/rules/file-operations.mdc b/.cursor/rules/file-operations.mdc new file mode 120000 index 00000000..c5030a9b --- /dev/null +++ b/.cursor/rules/file-operations.mdc @@ -0,0 +1 @@ +../../.claude/skills/file-operations/SKILL.md \ No newline at end of file diff --git a/.cursor/rules/file-utils.mdc b/.cursor/rules/file-utils.mdc deleted file mode 100644 index 9d1bb5a8..00000000 --- a/.cursor/rules/file-utils.mdc +++ /dev/null @@ -1,111 +0,0 @@ ---- -description: Standards for using file utilities in the StackOne repository -globs: *.ts -alwaysApply: false ---- - # File Utilities Standards - -Standards for using file utilities in the StackOne repository. - - -name: file_utils_standards -description: Standards for using file utilities from the file.ts module instead of direct fs/path operations - -filters: - - type: path - pattern: "^src/.*\\.ts$" - -actions: - - type: suggest - message: | - When working with files and directories: - - 1. Use the file utilities from `src/utils/file.ts`: - - Import the required utilities: `import { ... } from './utils/file'` - - Do not use fs/path modules directly unless absolutely necessary - - 2. Available utilities: - - `isBase64(str)`: Check if a string is base64 encoded - - `isValidFilePath(filePath)`: Check if a file path is valid and the file exists - - `readFileAsBase64(filePath)`: Read a file and return its contents as a base64 string - - `extractFileInfo(filePath)`: Extract file name and extension from a path - - `directoryExists(dirPath)`: Check if a directory exists - - `listFilesInDirectory(dirPath, filter?)`: List files in a directory with optional filtering - - `readJsonFile(filePath)`: Read and parse a JSON file with type safety - - `getFileNameWithoutExtension(filePath)`: Get file name without extension - - `joinPaths(...segments)`: Join path segments safely - - 3. Benefits of using these utilities: - - Consistent error handling - - Type safety - - Centralized file operations - - Easier testing and mocking - -examples: - - input: | - import fs from 'node:fs'; - import path from 'node:path'; - - function processJsonFile(filePath: string) { - if (fs.existsSync(filePath)) { - const content = fs.readFileSync(filePath, 'utf-8'); - const data = JSON.parse(content); - return data; - } - throw new Error(`File not found: ${filePath}`); - } - output: | - import { isValidFilePath, readJsonFile } from '../utils/file'; - - function processJsonFile(filePath: string): T { - if (isValidFilePath(filePath)) { - return readJsonFile(filePath); - } - throw new Error(`File not found: ${filePath}`); - } - - - input: | - import * as fs from 'node:fs'; - import * as path from 'node:path'; - - function getFilesInDirectory(dirPath: string) { - if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) { - return fs.readdirSync(dirPath).filter(file => file.endsWith('.json')); - } - return []; - } - output: | - import { directoryExists, listFilesInDirectory } from '../utils/file'; - - function getFilesInDirectory(dirPath: string): string[] { - if (directoryExists(dirPath)) { - return listFilesInDirectory(dirPath, file => file.endsWith('.json')); - } - return []; - } - - - input: | - import fs from 'node:fs'; - import path from 'node:path'; - - function getFileNameWithoutExt(filePath: string): string { - const fileName = path.basename(filePath); - const dotIndex = fileName.lastIndexOf('.'); - return dotIndex === -1 ? fileName : fileName.substring(0, dotIndex); - } - output: | - import { getFileNameWithoutExtension } from '../utils/file'; - - function getFileNameWithoutExt(filePath: string): string { - return getFileNameWithoutExtension(filePath); - } - -metadata: - priority: high - version: 1.0 - tags: - - files - - directories - - utilities - - standards - \ No newline at end of file diff --git a/.cursor/rules/json-schema-handling.mdc b/.cursor/rules/json-schema-handling.mdc deleted file mode 100644 index 6dbf5772..00000000 --- a/.cursor/rules/json-schema-handling.mdc +++ /dev/null @@ -1,110 +0,0 @@ ---- -description: Standards for working with JSON Schema types in the repository. -globs: *.ts -alwaysApply: false ---- -# JSON Schema Handling - -Standards for working with JSON Schema types in the repository. - - -name: json_schema_handling -description: Standards for properly handling JSON Schema types to avoid type errors - -filters: - - type: path - pattern: "^src/.*\\.ts$" - -actions: - - type: suggest - message: | - When working with JSON Schema types, follow these guidelines to avoid type errors: - - 1. Understanding JSONSchema7Definition type: - - `JSONSchema7Definition` is a union type that can be either a `JSONSchema7` object or a boolean - - It does NOT accept `undefined` as a valid value - - Setting a property to `undefined` will cause a type error - - 2. Handling the conflict between TypeScript types and linter rules: - - The TypeScript type system doesn't allow setting a `JSONSchema7Definition` property to `undefined` - - However, linters like Biome may prefer using `undefined` assignment over the `delete` operator for performance - - To satisfy both, use one of these approaches: - - 3. Recommended approaches for removing JSON Schema properties: - - Use type assertion when setting to undefined: `obj.properties['prop'] = undefined as unknown as JSONSchema7Definition` - - Create a new object without the property using destructuring: `const { propToRemove, ...rest } = obj.properties` - - Use a helper function that handles the type casting internally - - For complex objects, consider using a deep clone and filter approach - - 4. When modifying schema objects: - - Create a new object with spread syntax rather than modifying in place when possible - - Use proper type guards to ensure type safety - - Consider using a deep clone for complex nested schemas to avoid reference issues - - Always check if a property exists before attempting to modify it - -examples: - - input: | - // Problematic: Type error with undefined, linter warning with delete - function removeSchemaProperty(schema: { properties: Record }): void { - // TypeScript error: Type 'undefined' is not assignable to type 'JSONSchema7Definition' - schema.properties['propertyToRemove'] = undefined; - - // Linter warning: Avoid the delete operator which can impact performance - delete schema.properties['propertyToRemove']; - } - output: | - // Solution 1: Type assertion to satisfy TypeScript - function removeSchemaProperty(schema: { properties: Record }): void { - // Use type assertion to satisfy TypeScript while using undefined (preferred by linters) - schema.properties['propertyToRemove'] = undefined as unknown as JSONSchema7Definition; - } - - // Solution 2: Create a new object without the property - function removeSchemaProperty(schema: { properties: Record }): { properties: Record } { - const { propertyToRemove, ...rest } = schema.properties; - return { ...schema, properties: rest }; - } - - // Solution 3: Helper function approach - function removeJsonSchemaProperty(obj: Record, key: string): void { - // This function encapsulates the type assertion - obj[key] = undefined as unknown as T; - } - - function removeSchemaProperty(schema: { properties: Record }): void { - removeJsonSchemaProperty(schema.properties, 'propertyToRemove'); - } - - - input: | - // Incorrect: Not checking if properties exist - function processSchema(schema: JSONSchema7): void { - const requiredProps = schema.required; - requiredProps.forEach(prop => { - schema.properties[prop].description = 'This property is required'; - }); - } - output: | - // Correct: Checking if properties exist - function processSchema(schema: JSONSchema7): void { - if (!schema.required || !schema.properties) { - return; - } - - schema.required.forEach(prop => { - if (schema.properties && prop in schema.properties) { - const propSchema = schema.properties[prop]; - if (typeof propSchema === 'object' && propSchema !== null) { - propSchema.description = 'This property is required'; - } - } - }); - } - -metadata: - priority: high - version: 1.0 - tags: - - json-schema - - typescript - - type-safety - \ No newline at end of file diff --git a/.cursor/rules/native-fetch.mdc b/.cursor/rules/native-fetch.mdc deleted file mode 100644 index 719b25a4..00000000 --- a/.cursor/rules/native-fetch.mdc +++ /dev/null @@ -1,128 +0,0 @@ ---- -description: how to use fetch -globs: *.ts -alwaysApply: false ---- - # Native Fetch Standards - -Standards for using the native fetch API in the StackOne repository. - - -name: native_fetch_standards -description: Standards for using the native fetch API instead of external fetch implementations - -filters: - - type: path - pattern: "^src/.*\\.ts$" - -actions: - - type: suggest - message: | - When making HTTP requests: - - 1. Use the native fetch API: - - Node.js now includes a built-in fetch API, so external packages like node-fetch are no longer needed - - Do not import fetch from any external packages (e.g., `import fetch from 'node-fetch'`) - - Simply use the globally available `fetch` function - - 2. Error handling: - - Always check `response.ok` before processing the response - - Use try/catch blocks to handle network errors - - Provide meaningful error messages that include the URL and status code - - 3. Response processing: - - Use the appropriate method based on the expected response type: - - `response.json()` for JSON responses - - `response.text()` for text responses - - `response.arrayBuffer()` for binary data - - 4. Request configuration: - - Set appropriate headers (Content-Type, Authorization, etc.) - - Use the correct HTTP method (GET, POST, PUT, DELETE, etc.) - - For JSON requests, use `JSON.stringify()` for the body and set Content-Type to application/json - -examples: - - input: | - import fetch from 'node-fetch'; - - async function fetchData() { - const response = await fetch('https://api.example.com/data'); - return response.json(); - } - output: | - // No import needed for fetch - - async function fetchData() { - const response = await fetch('https://api.example.com/data'); - if (!response.ok) { - throw new Error(`API error: ${response.status} for https://api.example.com/data`); - } - return response.json(); - } - - - input: | - import { default as fetch } from 'node-fetch'; - - async function postData(data) { - const response = await fetch('https://api.example.com/data', { - method: 'POST', - body: JSON.stringify(data), - headers: { 'Content-Type': 'application/json' } - }); - const result = await response.json(); - return result; - } - output: | - async function postData(data) { - try { - const response = await fetch('https://api.example.com/data', { - method: 'POST', - body: JSON.stringify(data), - headers: { 'Content-Type': 'application/json' } - }); - - if (!response.ok) { - throw new Error(`API error: ${response.status} for https://api.example.com/data`); - } - - return await response.json(); - } catch (error) { - throw new Error(`Failed to post data: ${error.message}`); - } - } - - - input: | - import * as nodeFetch from 'node-fetch'; - - async function fetchWithAuth(token) { - const response = await nodeFetch.default('https://api.example.com/protected', { - headers: { 'Authorization': `Bearer ${token}` } - }); - return await response.json(); - } - output: | - async function fetchWithAuth(token) { - try { - const response = await fetch('https://api.example.com/protected', { - headers: { 'Authorization': `Bearer ${token}` } - }); - - if (!response.ok) { - throw new Error(`Auth API error: ${response.status} for https://api.example.com/protected`); - } - - return await response.json(); - } catch (error) { - throw new Error(`Authentication request failed: ${error.message}`); - } - } - -metadata: - priority: high - version: 1.0 - tags: - - fetch - - http - - api - - standards - \ No newline at end of file diff --git a/.cursor/rules/orama-integration.mdc b/.cursor/rules/orama-integration.mdc new file mode 120000 index 00000000..a69e7c34 --- /dev/null +++ b/.cursor/rules/orama-integration.mdc @@ -0,0 +1 @@ +../../.claude/skills/orama-integration/SKILL.md \ No newline at end of file diff --git a/.cursor/rules/pnpm-standards.mdc b/.cursor/rules/pnpm-standards.mdc deleted file mode 100644 index 62592e51..00000000 --- a/.cursor/rules/pnpm-standards.mdc +++ /dev/null @@ -1,48 +0,0 @@ ---- -description: Standards for using pnpm in this repository -globs: -alwaysApply: false ---- - -# pnpm Standards - -## Overview - -This repository uses [pnpm](https://pnpm.io) as the package manager. pnpm is a fast, disk space efficient package manager. - -## Package Management - -- Use `pnpm install` instead of `npm install` to add dependencies -- Use `pnpm-lock.yaml` for lockfiles (automatically generated) -- When adding new dependencies, use: `pnpm add package@x.y.z` - -## TypeScript Configuration - -- TypeScript is configured via `tsconfig.json` -- Use `pnpm typecheck` to run type checking with tsgo - -## Running Scripts - -- Use `pnpm