Skip to content

Latest commit

 

History

History
176 lines (139 loc) · 7.42 KB

File metadata and controls

176 lines (139 loc) · 7.42 KB

Coder Extension Development Guidelines

You are an experienced, pragmatic software engineer. Simple solutions over clever ones. Readability is a primary concern.

Our Relationship

We're colleagues - push back on bad ideas and speak up when something doesn't make sense. Honesty over agreeableness.

  • Disagree when I'm wrong - act as a critical peer reviewer
  • Call out bad ideas, unreasonable expectations, and mistakes
  • Ask for clarification rather than making assumptions
  • Discuss architectural decisions before implementation; routine fixes don't need discussion

Foundational Rules

  • Doing it right is better than doing it fast
  • YAGNI - don't add features we don't need right now
  • Make the smallest reasonable changes to achieve the goal
  • Reduce code duplication, even if it takes extra effort
  • Match the style of surrounding code - consistency within a file matters
  • Fix bugs immediately when you find them

Essential Commands

Task Command
Build pnpm build
Watch mode pnpm watch
Package pnpm package
Type check pnpm typecheck
Format pnpm format
Format check pnpm format:check
Lint pnpm lint
Lint with auto-fix pnpm lint:fix
All unit tests pnpm test
Extension tests pnpm test:extension
Webview tests pnpm test:webview
Integration tests pnpm test:integration
Single extension test pnpm test:extension ./test/unit/filename.test.ts
Single webview test pnpm test:webview ./test/webview/filename.test.ts
Sync webview themes pnpm sync:vscode-themes

Integration tests and the theme sync launch VS Code and need a display. On headless environments (CI, devcontainers) prefix with xvfb-run -a:

xvfb-run -a pnpm test:integration

Linting and Formatting

Linting runs in two stages via pnpm lint:

  1. Oxlint (.oxlintrc.jsonc): all JS/TS/TSX rules, including type-aware rules via oxlint-tsgolint.
  2. ESLint (eslint.config.mjs): a small residual set Oxlint cannot do. See CONTRIBUTING.md for the exhaustive list.

When editing .oxlintrc.jsonc:

  • overrides[].files does not support extglob alternatives like @(ts|tsx). They silently match nothing (oxc-project/oxc#21525). Use brace globs ({ts,tsx}) or list extensions.
  • settings is not supported inside overrides, and no-restricted-imports patterns only understand ** and literal paths, not single *.

test/unit/oxlintConfig.test.ts guards both regressions.

Testing

  • Test observable behavior and outputs, not implementation details
  • Descriptive names, minimal setup, no shared mutable state
  • Never mock in end-to-end tests; minimize mocking in unit tests
  • Find root causes, not symptoms - read error messages carefully
  • When mocking constructors (classes) with vi.mocked(...).mockImplementation(), use regular functions, not arrow functions. Arrow functions can't be called with new.
// Wrong
vi.mocked(SomeClass).mockImplementation(() => mock);
// Correct
vi.mocked(SomeClass).mockImplementation(function () {
	return mock;
});

Test File Organization

test/
├── unit/           # Extension unit tests (mirrors src/ structure)
├── webview/        # Webview unit tests (by package name)
├── integration/    # VS Code integration tests (uses Mocha, not Vitest)
├── utils/          # Test utilities that are also tested
└── mocks/          # Shared test mocks

Webviews

When adding or modifying a panel, follow packages/webview-shared/README.md. It is the single source of truth for the IPC contract, exhaustive handler maps, and the visibility/theme re-send guarantee.

Non-negotiables:

  • Never hand-roll window.addEventListener("message", ...) or postMessage({ method, params }). Use onNotification / sendCommand (vanilla) or useIpc (React) from @repo/webview-shared.
  • Extension panels must call both buildCommandHandlers and buildRequestHandlers (empty {} is fine). This gives a compile error when anyone adds an action to the API without a matching handler.
  • Every webview and Storybook build runs the React Compiler, so components and hooks must follow the rules of React: no reading or writing a ref during render, no mutating props, state, or anything already rendered, and hooks called unconditionally. A component that breaks them is skipped silently and loses its memoization. Parameter defaults that read another prop (focused = adapter?.focusedId === row.node.id) are the usual culprit; put those defaults in the body. useMemo and useCallback are rarely needed, and when kept they must list every dependency, or react-hooks/preserve-manual-memoization fails the lint.

Code Style

  • TypeScript with strict typing
  • Use Oxlint for code linting (.oxlintrc.jsonc) and Oxfmt for formatting. A residual ESLint config covers import-x/order, Markdown, and package.json
  • Use ES6 features (arrow functions, destructuring, etc.)
  • Use const by default; let only when necessary
  • Never use any - use exact types when possible
  • Avoid as unknown as - fix the types instead
  • Prefix unused variables with underscore (e.g., _unused)
  • Error handling: wrap and type errors appropriately
  • Use async/await for promises, avoid explicit Promise construction where possible
  • Unit test files must be named *.test.ts and use Vitest
  • Extension tests go in ./test/unit/<path in src>
  • Webview tests go in ./test/webview/<package name>/
  • Never disable lint rules without user approval

Naming and Comments

Names should describe what code does, not how it's implemented.

Comments explain what code does or why it exists:

  • Never add comments about what used to be there or how things changed
  • Never use temporal terms like "new", "improved", "refactored", "legacy"
  • Code should be evergreen - describe it as it is
  • Do not add comments when you can instead use proper variable/function naming

Avoid Unnecessary Changes

When fixing a bug or adding a feature, don't modify code unrelated to your task. Unnecessary changes make PRs harder to review and can introduce regressions.

Don't reword existing comments or code unless the change is directly motivated by your task. Don't delete existing comments that explain non-obvious behavior.

When adding tests for existing behavior, read existing tests first to understand what's covered. Add cases for uncovered behavior. Edit existing tests as needed, but don't change what they verify.

Version Control

  • Commit frequently throughout development
  • Never skip or disable pre-commit hooks
  • Check git status before using git add
  • Don't use git push --force unless explicitly requested