Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
109 changes: 4 additions & 105 deletions .claude/skills/file-operations/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,105 +1,11 @@
---
name: file-operations
description: File operations and HTTP request standards for StackOne SDK
description: HTTP request standards for StackOne SDK
---

# File Operations and HTTP Standards
# HTTP Request Standards

This skill provides guidance on file operations and HTTP request patterns in the StackOne SDK.

## Using File Utilities

When working with files and directories, use the utilities from `src/utils/file.ts` instead of direct `fs`/`path` operations.

### Available Utilities

Import the required utilities:
```typescript
import {
isBase64,
isValidFilePath,
readFileAsBase64,
extractFileInfo,
directoryExists,
listFilesInDirectory,
readJsonFile,
getFileNameWithoutExtension,
joinPaths,
} from '../utils/file';
```

### Utility Functions

- **`isBase64(str: string): boolean`** - Check if a string is base64 encoded
- **`isValidFilePath(filePath: string): boolean`** - Check if a file path is valid and the file exists
- **`readFileAsBase64(filePath: string): string`** - Read a file and return its contents as base64
- **`extractFileInfo(filePath: string)`** - Extract file name and extension from a path
- **`directoryExists(dirPath: string): boolean`** - Check if a directory exists
- **`listFilesInDirectory(dirPath: string, filter?: (file: string) => boolean): string[]`** - List files in a directory with optional filtering
- **`readJsonFile<T>(filePath: string): T`** - Read and parse a JSON file with type safety
- **`getFileNameWithoutExtension(filePath: string): string`** - Get file name without extension
- **`joinPaths(...segments: string[]): string`** - Join path segments safely

### Benefits

- Consistent error handling across the codebase
- Type safety with generics
- Centralized file operations
- Easier to test and mock
- Prevents direct fs/path dependency scatter

### Examples

**Bad - Direct fs/path usage**:
```typescript
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}`);
}
```

**Good - Using file utilities**:
```typescript
import { isValidFilePath, readJsonFile } from '../utils/file';

function processJsonFile<T>(filePath: string): T {
if (isValidFilePath(filePath)) {
return readJsonFile<T>(filePath);
}
throw new Error(`File not found: ${filePath}`);
}
```

**Bad - Direct directory operations**:
```typescript
import * as fs from 'node:fs';

function getJsonFiles(dirPath: string): string[] {
if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
return fs.readdirSync(dirPath).filter(file => file.endsWith('.json'));
}
return [];
}
```

**Good - Using file utilities**:
```typescript
import { directoryExists, listFilesInDirectory } from '../utils/file';

function getJsonFiles(dirPath: string): string[] {
if (directoryExists(dirPath)) {
return listFilesInDirectory(dirPath, file => file.endsWith('.json'));
}
return [];
}
```
This skill provides guidance on HTTP request patterns in the StackOne SDK.

## Native Fetch API Standards

Expand Down Expand Up @@ -213,16 +119,9 @@ async function getProtectedData(token: string): Promise<Data> {
}
```

## When to Use Direct fs/path

Only use direct `fs`/`path` operations when:
- The utility function doesn't exist for your use case
- You have a specific performance requirement
- Document why you're bypassing the utilities

## When to Use Direct HTTP Clients

Only use specialized HTTP clients when:
Only use specialised HTTP clients when:
- You need advanced features not covered by fetch (e.g., interceptors, retries)
- You're integrating with a framework that requires it
- Document why you're not using native fetch
111 changes: 0 additions & 111 deletions .cursor/rules/file-utils.mdc

This file was deleted.

6 changes: 2 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,10 @@ See the **typescript-patterns** skill for TypeScript best practices:

Refer to `.claude/skills/typescript-patterns/SKILL.md` for complete details.

## File Operations and HTTP Standards
## HTTP Standards

See the **file-operations** skill for file and HTTP guidance:
- Using `src/utils/file.ts` utilities instead of direct fs/path
See the **file-operations** skill for HTTP guidance:
- Native fetch API standards and error handling
- Type-safe file operations
- Common HTTP request patterns

Refer to `.claude/skills/file-operations/SKILL.md` for complete details.
Expand Down
1 change: 0 additions & 1 deletion examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"@ai-sdk/openai": "catalog:dev",
"@types/node": "catalog:dev",
"ai": "catalog:peer",
"nano-spawn": "catalog:dev",
"openai": "catalog:peer"
},
"devEngines": {
Expand Down
19 changes: 19 additions & 0 deletions knip.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { KnipConfig } from 'knip'

export default {
workspaces: {
'.': {
entry: ['src/index.ts', 'mocks/**/*.ts'],
project: ['src/**/*.ts', 'mocks/**/*.ts']
},
examples: {
entry: ['*.ts'],
project: ['*.ts']
}
},
ignore: ['**/*.test.ts', '**/*.spec.ts', '**/*.test-d.ts'],
ignoreBinaries: ['only-allow'],
rules: {
optionalPeerDependencies: 'off'
}
} satisfies KnipConfig
4 changes: 4 additions & 0 deletions lefthook.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ pre-commit:
glob: "*.{ts,tsx,js,jsx,mts,cts,json,jsonc,yaml,yml,md}"
run: pnpm biome check --no-errors-on-unmatched --write {staged_files}
stage_fixed: true
knip:
glob: "*.{ts,tsx,js,jsx,mts,cts}"
run: pnpm run format:knip
stage_fixed: true
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@
],
"scripts": {
"build": "tsdown",
"format": "biome format --write .",
"lint": "biome check .",
"format": "pnpm --no-bail --aggregate-output run '/^format:/'",
"format:biome": "biome format --write .",
"format:knip": "knip --fix --no-exit-code",
"lint": "pnpm --no-bail --aggregate-output run '/^lint:/'",
"lint:biome": "biome check .",
"lint:knip": "knip",
"preinstall": "npx only-allow pnpm",
"prepack": "npm pkg delete scripts.preinstall && pnpm run build",
"test": "pnpm --no-bail --aggregate-output run '/^test:/'",
Expand All @@ -36,7 +40,6 @@
"json-schema": "catalog:prod"
},
"devDependencies": {
"@ai-sdk/openai": "catalog:dev",
"@ai-sdk/provider-utils": "catalog:dev",
"@biomejs/biome": "catalog:dev",
"@hono/mcp": "catalog:dev",
Expand All @@ -45,8 +48,8 @@
"@typescript/native-preview": "catalog:dev",
"@vitest/coverage-v8": "catalog:dev",
"ai": "catalog:peer",
"fs-fixture": "catalog:dev",
"hono": "catalog:dev",
"knip": "catalog:dev",
"lefthook": "catalog:dev",
"msw": "catalog:dev",
"openai": "catalog:peer",
Expand Down
Loading
Loading