Skip to content

Latest commit

Β 

History

History
424 lines (309 loc) Β· 19.7 KB

File metadata and controls

424 lines (309 loc) Β· 19.7 KB

CLAUDE.md

MANDATORY: Act as principal-level engineer. Follow these guidelines exactly.

CANONICAL REFERENCE

This is a reference to shared Socket standards. See ../socket-registry/CLAUDE.md for canonical source.

πŸ‘€ USER CONTEXT

  • Identify users by git credentials: Extract name from git commit author, GitHub account, or context
  • 🚨 When identity is verified: ALWAYS use their actual name - NEVER use "the user" or "user"
  • Direct communication: Use "you/your" when speaking directly to the verified user
  • Discussing their work: Use their actual name when referencing their commits/contributions
  • Example: If git shows "John-David Dalton jdalton@example.com", refer to them as "John-David"
  • Other contributors: Use their actual names from commit history/context

PRE-ACTION PROTOCOL

MANDATORY: Review CLAUDE.md before any action. No exceptions.

VERIFICATION PROTOCOL

MANDATORY: Before claiming any task is complete:

  1. Test the solution end-to-end
  2. Verify all changes work as expected
  3. Run the actual commands to confirm functionality
  4. Never claim "Done" without verification

Critical Rules

Fix ALL Issues

  • Fix ALL issues when asked - Never dismiss issues as "pre-existing" or "not caused by my changes"
  • When asked to fix, lint, or check: fix everything found, regardless of who introduced it
  • Always address all issues found during lint/check operations

ABSOLUTE RULES

  • Never create files unless necessary
  • Always prefer editing existing files
  • Forbidden to create docs unless requested
  • Required to do exactly what was asked

ROLE

Principal Software Engineer: production code, architecture, reliability, ownership.

EVOLUTION

If user repeats instruction 2+ times, ask: "Should I add this to CLAUDE.md?"

πŸ“š SHARED STANDARDS

Canonical reference: ../socket-registry/CLAUDE.md

All shared standards (git, testing, code style, cross-platform, CI) defined in socket-registry/CLAUDE.md.

Quick references:

  • Commits: Conventional Commits <type>(<scope>): <description> - NO AI attribution
  • Scripts: Prefer pnpm run foo --flag over foo:bar scripts
  • Dependencies: After package.json edits, run pnpm install to update pnpm-lock.yaml
  • Backward Compatibility: 🚨 FORBIDDEN to maintain - actively remove when encountered (see canonical CLAUDE.md)
  • Work Safeguards: MANDATORY commit + backup branch before bulk changes
  • Safe Deletion: Use safeDelete() from @socketsecurity/lib/fs (NEVER fs.rm/rmSync or rm -rf)

Documentation Policy

🚨 CRITICAL: Do NOT litter the repository with documentation files.

Allowed documentation locations:

  • docs/ - Primary documentation folder (lowercase-with-hyphens.md filenames, pithy writing with visuals)
  • README.md - Root project README only
  • CHANGELOG.md - Root changelog only
  • SECURITY.md - Root security policy only
  • CLAUDE.md - Root project instructions only
  • packages/*/README.md - Package-specific READMEs only
  • test/fixtures/*/README.md - Test fixture explanations only (when fixtures are complex)
  • test/*/README.md - Test suite architecture docs only (e.g., test/e2e/README.md, test/helpers/README.md)

Forbidden documentation locations:

  • ❌ .claude/*.md - No temporary analysis docs, architectural notes, coverage reports
  • ❌ Root directory clutter - No ad-hoc markdown files
  • ❌ Scattered docs - No documentation outside approved locations

When creating documentation:

  1. Ask: Does this belong in docs/? (99% of the time, yes)
  2. Use descriptive lowercase-with-hyphens.md filenames
  3. Keep writing pithy and focused
  4. Include visuals where helpful
  5. Never create temporary/scratch documentation files

CLI-SPECIFIC

Commands

Development Commands

  • Build: pnpm run build (smart build, skips unchanged)
  • Build force: pnpm run build --force (force rebuild CLI + SEA for current platform)
  • Build SEA: pnpm run build:sea (build SEA binaries for all platforms)
  • Build CLI: pnpm run build:cli (CLI package only)
  • Test: pnpm test (runs check + all tests from monorepo root)
  • Test unit only: pnpm --filter @socketsecurity/cli run test:unit
  • Lint: pnpm run lint (uses oxlint)
  • Type check: pnpm run type (uses tsc)
  • Check all: pnpm run check (lint + typecheck)
  • Fix all issues: pnpm run fix (auto-fix linting and formatting)
  • Commit without tests: git commit --no-verify (skips pre-commit hooks including tests)

Binary Build Notes

  • Node-smol binaries: Downloaded from socket-btm releases (not built locally)
  • Yoga WASM: Downloaded from socket-btm releases (not built locally)
  • SEA binaries: Built by injecting CLI blob into downloaded node-smol binaries
  • Output location: packages/package-builder/build/{dev|prod}/out/socketbin-cli-<platform>-<arch>/socket
  • Cache location: Build assets in packages/build-infra/build/downloaded/, DLX packages and VFS-extracted tools in ~/.socket/_dlx/

Testing Best Practices - CRITICAL: NO -- FOR FILE PATHS

  • 🚨 NEVER USE -- BEFORE TEST FILE PATHS - This runs ALL tests, not just your specified files!
  • Always build before testing: Run pnpm run build:cli before running tests to ensure dist files are up to date.
  • Test all: βœ… CORRECT: pnpm test (from monorepo root)
  • Test single file: βœ… CORRECT: pnpm --filter @socketsecurity/cli run test:unit src/commands/specific/cmd-file.test.mts
    • ❌ WRONG: pnpm test:unit src/commands/specific/cmd-file.test.mts (command not found at root!)
    • ❌ WRONG: pnpm --filter @socketsecurity/cli run test:unit -- src/commands/specific/cmd-file.test.mts (runs ALL tests!)
  • Test multiple files: βœ… CORRECT: pnpm --filter @socketsecurity/cli run test:unit file1.test.mts file2.test.mts
  • Test with pattern: βœ… CORRECT: pnpm --filter @socketsecurity/cli run test:unit src/commands/specific/cmd-file.test.mts -t "pattern"
    • ❌ WRONG: pnpm --filter @socketsecurity/cli run test:unit -- src/commands/specific/cmd-file.test.mts -t "pattern"
  • Update snapshots:
    • All tests: pnpm testu (builds first, then updates all snapshots)
    • Single file: βœ… CORRECT: pnpm testu src/commands/specific/cmd-file.test.mts
    • ❌ WRONG: pnpm testu -- src/commands/specific/cmd-file.test.mts (updates ALL snapshots!)
  • Update with --update flag: pnpm --filter @socketsecurity/cli run test:unit src/commands/specific/cmd-file.test.mts --update
  • Timeout for long tests: Use timeout command or specify in test file.

Git Commit Guidelines

  • Follow Conventional Commits style
  • 🚨 FORBIDDEN: NO AI attribution in commits (see SHARED STANDARDS)

Running the CLI locally

  • Watch mode: pnpm dev (auto-rebuilds on file changes)
  • Build and run: pnpm build:cli && node packages/cli/dist/index.js
  • Run built version: node packages/cli/dist/index.js <args> (requires prior build)

Note: Avoid pnpm exec socket if you have a global socket installation, as it may conflict with the local package.

Package Management

  • Package Manager: This project uses pnpm (v10.22+)
  • Install dependencies: pnpm install
  • Add dependency: pnpm add <package>
  • Add dev dependency: pnpm add -D <package>
  • Update dependencies: pnpm update
  • Override behavior: pnpm.overrides in package.json controls dependency versions across the entire project
  • Using $ syntax: "$package-name" in overrides means "use the version specified in dependencies"

Architecture

This is a CLI tool for Socket.dev security analysis, built with TypeScript using .mts extensions.

Core Structure

  • Entry point: src/cli.mts - Main CLI entry with meow subcommands
  • Commands: src/commands.mts - Exports all command definitions
  • Command modules: src/commands/*/ - Each feature has its own directory with cmd-, handle-, and output-* files
  • Utilities: src/utils/ - Shared utilities for API, config, formatting, etc.
  • Constants: src/constants.mts - Application constants
  • Types: src/types.mts - TypeScript type definitions

Command Architecture Pattern

βœ… PREFERRED: Consolidated Pattern for Simple Commands

For commands with straightforward logic (no subcommands, < 200 lines total), consolidate into a single cmd-*.mts file:

// Single cmd-*.mts file structure:
import { getDefaultLogger } from '@socketsecurity/lib/logger'
// ... other imports

const logger = getDefaultLogger()

export const CMD_NAME = 'command-name'
const description = 'Command description'
const hidden = false

// Types.
interface CommandResult {
  // Type definitions here.
}

// Helper functions.
function helperFunction(): void {
  // Helper logic here.
}

// Command handler.
async function run(
  argv: string[] | readonly string[],
  importMeta: ImportMeta,
  { parentName }: CliCommandContext,
): Promise<void> {
  const config: CliCommandConfig = {
    /* ... */
  }
  const cli = meowOrExit({ argv, config, importMeta, parentName })

  // Command logic here.
}

// Exported command.
export const cmdCommandName = {
  description,
  hidden,
  run,
}

Benefits:

  • All command logic in one file for easy navigation
  • Clear sections: imports β†’ constants β†’ types β†’ helpers β†’ handler β†’ export
  • Reduced file count (3 files β†’ 1 file)
  • Maintained compatibility with existing meow-based CLI architecture

Examples: whoami, logout (consolidated)

⚠️ Legacy Pattern for Complex Commands

Complex commands with subcommands or > 200 lines should keep the modular pattern:

  • cmd-*.mts - Command definition and CLI interface
  • handle-*.mts - Business logic and processing
  • output-*.mts - Output formatting (JSON, markdown, etc.)
  • fetch-*.mts - API calls (where applicable)

Examples: scan, organization, repository (keep modular)

Key Command Categories

  • npm/npx wrapping: socket npm, socket npx - Wraps npm/npx with security scanning
  • Scanning: socket scan - Create and manage security scans
  • Organization management: socket organization - Manage org settings and policies
  • Package analysis: socket package - Analyze package scores
  • Optimization: socket optimize - Apply Socket registry overrides
  • Configuration: socket config - Manage CLI configuration

Update Mechanism

Socket CLI has different update mechanisms depending on installation method:

SEA Binaries (Standalone Executables)

  • Update checking: Handled by node-smol C stub via embedded --update-config
  • Configuration: Embedded during build in packages/cli/scripts/sea-build-utils/builder.mjs
  • GitHub releases: Checks https://api.github.com/repos/SocketDev/socket-cli/releases
  • Tag pattern: Matches socket-cli-* (e.g., socket-cli-20260127-abc1234)
  • Notification: Shown on CLI exit (non-blocking)
  • Update command: socket self-update (handled by node-smol, not TypeScript CLI)
  • Environment variable: SOCKET_CLI_SKIP_UPDATE_CHECK=1 to disable

npm/pnpm/yarn Installations

  • Update checking: TypeScript-based in src/utils/update/manager.mts
  • Registry: Checks npm registry for socket package
  • Notification: Shown on CLI exit (non-blocking)
  • Update command: Use package manager (e.g., npm update -g socket)
  • Environment variable: SOCKET_CLI_SKIP_UPDATE_CHECK=1 to disable

Key Implementation Details

  • scheduleUpdateCheck() in manager.mts skips when isSeaBinary() returns true
  • SEA binaries use embedded update-config.json (1112 bytes)
  • node-smol handles HTTP requests via embedded libcurl
  • Update checks respect CI/TTY detection and rate limiting

Build System

  • Uses esbuild for building distribution files
  • TypeScript compilation with tsgo
  • Environment config (.env.test for testing)
  • Linting with Oxlint
  • Formatting with Oxfmt

Testing

  • Vitest for unit testing
  • Test files use .test.mts extension
  • Fixtures in test/fixtures/
  • Coverage reporting available

External Dependencies

  • Vendored modules in src/external/ (e.g., ink-table)
  • Dependencies bundled into dist/cli.js via esbuild
  • Uses Socket registry overrides for security
  • Custom patches applied to dependencies in patches/

Environment and Configuration

Environment Files

  • .env.test - Test environment configuration

Configuration Files

  • .oxfmtrc.json - Oxfmt formatter configuration
  • .oxlintrc.json - Oxlint linter configuration
  • vitest.config.mts - Vitest test runner configuration
  • tsconfig.json - Main TypeScript configuration
  • tsconfig.dts.json - TypeScript configuration for type definitions

Package Structure

  • Binary entries: socket, socket-npm, socket-npx (defined in package.json bin field, pointing to dist/index.js)
  • Distribution: Built files go to dist/ directory
  • External dependencies: Bundled into dist/cli.js via esbuild
  • Test fixtures: Located in test/fixtures/

Dependency Management

  • Uses Socket registry overrides for enhanced alternatives
  • Custom patches applied to dependencies via custompatch
  • Overrides specified in package.json for enhanced alternatives

Changelog Management

Follow Keep a Changelog format. Include user-facing changes only: Added, Changed, Fixed, Removed. Exclude: dependency updates, refactoring, tests, CI/CD, formatting. Marketing voice, stay concise.

Third-Party Integrations

Socket CLI integrates with various third-party tools and services:

  • @coana-tech/cli: Static analysis tool for reachability analysis and vulnerability detection
  • cdxgen: CycloneDX BOM generator for creating software bill of materials
  • synp: Tool for converting between yarn.lock and package-lock.json formats

πŸ”§ Code Style (MANDATORY)

πŸ“ File Organization

  • File extensions: Use .mts for TypeScript module files
  • Import order: Node.js built-ins first, then third-party packages, then local imports
  • Import grouping: Group imports by source (Node.js, external packages, local modules)
  • Type imports: 🚨 ALWAYS use separate import type statements for TypeScript types, NEVER mix runtime imports with type imports in the same statement
    • βœ… CORRECT: import { readPackageJson } from '@socketsecurity/registry/lib/packages' followed by import type { PackageJson } from '@socketsecurity/registry/lib/packages'
    • ❌ FORBIDDEN: import { readPackageJson, type PackageJson } from '@socketsecurity/registry/lib/packages'

Naming Conventions

  • Constants: Use UPPER_SNAKE_CASE for constants (e.g., CMD_NAME, REPORT_LEVEL)
  • Files: Use kebab-case for filenames (e.g., cmd-scan-create.mts, handle-create-new-scan.mts)
  • Variables: Use camelCase for variables and functions

πŸ—οΈ Code Structure (CRITICAL PATTERNS)

  • Command pattern: Complex commands use modular pattern (cmd-*.mts, handle-*.mts, output-*.mts); simple commands use consolidated single cmd-*.mts file
  • Type definitions: 🚨 ALWAYS use import type for better tree-shaking
  • Flags: 🚨 MUST use MeowFlags type with descriptive help text
  • Error handling: 🚨 REQUIRED - Use custom error types AuthError and InputError
  • Array destructuring: Use object notation { 0: key, 1: data } instead of array destructuring [key, data]
  • Dynamic imports: 🚨 FORBIDDEN - Never use dynamic imports (await import()). Always use static imports at the top of the file
  • Sorting: 🚨 MANDATORY - Always sort lists, exports, and items in documentation headers alphabetically/alphanumerically for consistency
  • Comment placement: Place comments on their own line, not to the right of code
  • Comment formatting: Use fewer hyphens/dashes and prefer commas, colons, or semicolons for better readability
  • Await in loops: When using await inside for-loops, sequential processing is acceptable when iterations depend on each other
  • If statement returns: Never use single-line return if statements; always use proper block syntax with braces
  • List formatting: Use - for bullet points in text output, not β€’ or other Unicode characters, for better terminal compatibility
  • Existence checks: Perform simple existence checks first before complex operations
  • Destructuring order: Sort destructured properties alphabetically in const declarations
  • Function ordering: Place functions in alphabetical order, with private functions first, then exported functions
  • GitHub API calls: Use Octokit instances from src/utils/github.mts (getOctokit(), getOctokitGraphql()) instead of raw fetch calls for GitHub API interactions
  • Object mappings: Use objects with __proto__: null (not undefined) for static string-to-string mappings and lookup tables to prevent prototype pollution; use Map for dynamic collections that will be mutated
  • Mapping constants: Move static mapping objects outside functions as module-level constants with descriptive UPPER_SNAKE_CASE names
  • Array length checks: Use !array.length instead of array.length === 0. For array.length > 0, use !!array.length when function must return boolean, or array.length when used in conditional contexts
  • Catch parameter naming: Use catch (e) instead of catch (error) for consistency across the codebase
  • Node.js fs imports: 🚨 MANDATORY pattern - import { someSyncThing, promises as fs } from 'node:fs'
  • Process spawning: 🚨 FORBIDDEN to use Node.js built-in child_process.spawn - MUST use spawn from @socketsecurity/registry/lib/spawn
  • Number formatting: 🚨 REQUIRED - Use underscore separators (e.g., 20_000) for large numeric literals. 🚨 FORBIDDEN - Do NOT modify number values inside strings

Error Handling

  • Input validation errors: Use InputError from src/utils/errors.mts for user input validation failures (missing files, invalid arguments, etc.)
  • Authentication errors: Use AuthError from src/utils/errors.mts for API authentication issues
  • CResult pattern: Use CResult<T> type for functions that can fail, following the Result/Either pattern with ok: true/false
  • Process exit: Avoid process.exit(1) unless absolutely necessary; prefer throwing appropriate error types that the CLI framework handles
  • Error messages: Write clear, actionable error messages that help users understand what went wrong and how to fix it
  • Examples:
    • βœ… throw new InputError('No .socket directory found in current directory')
    • βœ… throw new AuthError('Invalid API token')
    • ❌ logger.error('Error occurred'); return (doesn't set proper exit code)
    • ❌ process.exit(1) (bypasses error handling framework)

Safe File Operations (SECURITY CRITICAL)

  • File deletion: See SHARED STANDARDS section
  • 🚨 Use safeDelete() from @socketsecurity/lib/fs (NEVER fs.rm/rmSync or rm -rf)

Debugging and Troubleshooting

  • CI vs Local Differences: CI uses published npm packages, not local versions. Be defensive when using @socketsecurity/registry features
  • File Existence Checks: ALWAYS use existsSync() from node:fs, NEVER use fs.access() or fs.promises.access() for file/directory existence checks. existsSync() is synchronous, more direct, and the established pattern in this codebase for consistency

Formatting

  • Linting: Uses Oxlint with TypeScript and import plugins
  • Formatting: Uses Oxfmt for code formatting with 2-space indentation
  • Line length: Target 80 character line width where practical

Quality Standards

  • Code MUST pass all existing lints and type checks
  • All patterns MUST follow established codebase conventions
  • Error handling MUST be robust and user-friendly
  • Performance considerations MUST be evaluated for any changes