Skip to content

Latest commit

 

History

History
119 lines (84 loc) · 4.53 KB

AGENTS.md

File metadata and controls

119 lines (84 loc) · 4.53 KB

AGENTS.md

This file provides guidance for AI coding assistants working with the Craft codebase.

Package Management

  • Always use pnpm for package management. Never use npm or yarn.
  • Node.js version is managed by Volta (currently v22.12.0).
  • Install dependencies with pnpm install --frozen-lockfile.

Development Commands

Command Description
pnpm build Build the project (outputs to dist/craft)
pnpm test Run tests
pnpm lint Run ESLint
pnpm fix Auto-fix lint issues

To manually test changes:

pnpm build && ./dist/craft

Code Style

  • TypeScript is used throughout the codebase.
  • Prettier 3.x with single quotes and no arrow parens (configured in .prettierrc.yml).
  • ESLint 9.x with flat config (eslint.config.mjs) using typescript-eslint.
  • Unused variables prefixed with _ are allowed (e.g., _unusedParam).

Project Structure

src/
├── __mocks__/          # Test mocks
├── __tests__/          # Test files (*.test.ts)
├── artifact_providers/ # Artifact provider implementations
├── commands/           # CLI command implementations
├── schemas/            # Valibot schemas and TypeScript types for config
├── status_providers/   # Status provider implementations
├── targets/            # Release target implementations
├── types/              # Shared TypeScript types
├── utils/              # Utility functions
├── config.ts           # Configuration loading
├── index.ts            # CLI entry point
└── logger.ts           # Logging utilities
dist/
└── craft               # Single bundled executable (esbuild output)

Testing

  • Tests use Vitest.
  • Test files are located in src/__tests__/ and follow the *.test.ts naming pattern.
  • Run tests with pnpm test.
  • Use vi.fn(), vi.mock(), vi.spyOn() for mocking (Vitest's mock API).

CI/CD

  • Main branch is master.
  • CI runs tests on Node.js 20 and 22.
  • Craft releases itself using its own tooling (dogfooding).

Configuration

  • Project configuration lives in .craft.yml at the repository root.
  • The configuration schema is defined in src/schemas/.

Dry-Run Mode

Craft supports a --dry-run flag that prevents destructive operations. This is implemented via a centralized abstraction layer.

How It Works

Instead of checking isDryRun() manually in every function, destructive operations are wrapped with dry-run-aware proxies:

  • Git operations: Use getGitClient() from src/utils/git.ts or createGitClient(directory) for working with specific directories
  • GitHub API: Use getGitHubClient() from src/utils/githubApi.ts
  • File writes: Use safeFs from src/utils/dryRun.ts
  • Other actions: Use safeExec() or safeExecSync() from src/utils/dryRun.ts

ESLint Enforcement

ESLint rules prevent direct usage of raw APIs:

  • no-restricted-imports: Blocks direct simple-git imports
  • no-restricted-syntax: Blocks new Octokit() instantiation

If you're writing a wrapper module that needs raw access, use:

// eslint-disable-next-line no-restricted-imports -- This is the wrapper module
import simpleGit from 'simple-git';

Adding New Destructive Operations

When adding new code that performs destructive operations:

  1. Git: Get the git client via getGitClient() or createGitClient() - mutating methods are automatically blocked
  2. GitHub API: Get the client via getGitHubClient() - create*, update*, delete*, upload* methods are automatically blocked
  3. File writes: Use safeFs.writeFile(), safeFs.unlink(), etc. instead of raw fs methods
  4. Other: Wrap with safeExec(action, description) for custom operations

Special Cases

Some operations need explicit isDryRun() checks:

  • Commands with their own --dry-run flag (e.g., dart pub publish --dry-run in pubDev target)
  • Operations that need to return mock data in dry-run mode
  • User experience optimizations (e.g., skipping sleep timers)

Long-term Knowledge

For long-term knowledge entries managed by lore (gotchas, patterns, decisions, architecture), see .lore.md in the project root.