From 85c894dc4f6d6116a4261b04d8bfcb2c7e5ad8e7 Mon Sep 17 00:00:00 2001 From: Koen Kanters Date: Wed, 8 Oct 2025 22:11:10 +0200 Subject: [PATCH] chore: Update AGENTS.md and copilot-instructions.md (#28966) --- .github/copilot-instructions.md | 484 +++++++++++++++++++++++++++++--- AGENTS.md | 386 +++++++++++++++++++++++++ 2 files changed, 836 insertions(+), 34 deletions(-) create mode 100644 AGENTS.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index dd12c882f..75221de60 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,43 +1,459 @@ -# Copilot Coding Agent Instructions for Koenkk/zigbee2mqtt +# GitHub Copilot Instructions -Welcome! These instructions help ensure Copilot Coding Agent can efficiently collaborate on this repository. +## Priority Guidelines -## 1. Codebase Overview -- **Main language:** JavaScript (Node.js), TypeScript -- **Purpose:** Zigbee to MQTT bridge for home automation. -- **Core directories:** - - `src/`: Main source code (device adapters, communication, logic). - - `test/`: Automated tests. - - `docs/`: Documentation. - - `data/`: Configuration and database +When generating code for this repository: -## 2. Preferred Practices -- **Branching:** Use feature branches (`feat/xyz`) for enhancements and `fix/xyz` for bug fixes. -- **Commits:** Write clear, descriptive commit messages (imperative mood, < 72 chars). -- **Pull Requests:** Reference related issues, provide context, and include before/after behavior if modifying logic. Tag with appropriate labels. -- **Testing:** All code changes should include or update relevant tests. A test coverage of 100% is enforced. Run `npm test:coverage` before submitting PRs. -- **Linting:** Code must pass lint and formatting checks (`npm run check`). Use Biome for formatting. -- **Documentation:** Update relevant docs when adding features or changing behavior. +1. **Version Compatibility**: Always detect and respect the exact versions of languages, frameworks, and libraries used in this project +2. **Context Files**: Prioritize patterns and standards defined in the .github/copilot directory +3. **Codebase Patterns**: When context files don't provide specific guidance, scan the codebase for established patterns +4. **Architectural Consistency**: Maintain our layered architectural style with clear separation between controller, extensions, models, and utilities +5. **Code Quality**: Prioritize maintainability, performance, security, and testability in all generated code -## 3. Review & Feedback -- All PRs require review by maintainers. -- Automated checks must pass before merging. -- If you’re fixing a bug, include steps to reproduce in the PR description. +## Technology Stack -## 4. Security & Secrets -- Do not commit secrets, credentials, or private keys. -- Follow the repository’s security policy for vulnerability disclosures. +### Core Technologies +- **Language**: TypeScript 5.9.3 with target `esnext` and module `NodeNext` +- **Runtime**: Node.js ^20 || ^22 || ^24 +- **Package Manager**: pnpm 10.12.1 +- **Testing**: Vitest 3.1.1 with @vitest/coverage-v8 +- **Linting/Formatting**: Biome 2.2.5 (configured with 4-space indents, 150 line width, no bracket spacing) -## 5. Communication -- Use Discussions and Issues for questions and proposals. -- Respect community guidelines and code of conduct. +### Key Dependencies +- **zigbee-herdsman**: 6.2.0 (exact version - critical for Zigbee protocol compatibility) +- **zigbee-herdsman-converters**: 25.42.0 (exact version - device definitions) +- **MQTT**: mqtt 5.14.1 +- **Logging**: winston 3.18.3 +- **YAML**: js-yaml 4.1.0 +- **Decorators**: bind-decorator 1.0.11 +- **WebSocket**: ws 8.18.1 -## 6. Special Instructions for Copilot Coding Agent -- Suggest code changes that strictly adhere to existing styles and patterns. -- Explain reasoning in PR descriptions when implementing complex changes. -- Prioritize backward compatibility unless otherwise specified. -- If uncertain, prompt for clarification via PR comment before proceeding. +### TypeScript Configuration +- **Strict Mode**: Enabled with `noImplicitAny` and `noImplicitThis` +- **Module System**: NodeNext with ESM interop +- **Decorators**: Experimental decorators enabled +- **Composite**: True (for project references) +- **Source Maps**: Inline source maps enabled +- **Output**: Compiled to `dist/` directory ---- +## Project Architecture -For more details, see [Best practices for Copilot coding agent in your repository](https://gh.io/copilot-coding-agent-tips) and the repository's CONTRIBUTING.md. \ No newline at end of file +### Directory Structure +``` +lib/ # Source TypeScript files +├── controller.ts # Main controller orchestrating all components +├── mqtt.ts # MQTT client management +├── zigbee.ts # Zigbee network management +├── state.ts # State management +├── eventBus.ts # Event-driven communication +├── extension/ # Extension system (plugins) +│ ├── extension.ts # Abstract base class +│ ├── availability.ts +│ ├── bind.ts +│ ├── bridge.ts +│ ├── configure.ts +│ └── ... +├── model/ # Domain models +│ ├── device.ts +│ └── group.ts +├── util/ # Utility functions +│ ├── logger.ts +│ ├── settings.ts +│ ├── utils.ts +│ └── ... +└── types/ # TypeScript type definitions + └── api.ts +test/ # Vitest test files +data/ # Runtime configuration and data +``` + +### Architectural Patterns + +#### Extension Pattern +All extensions inherit from the abstract `Extension` base class: +```typescript +abstract class Extension { + protected zigbee: Zigbee; + protected mqtt: Mqtt; + protected state: State; + protected publishEntityState: PublishEntityState; + protected eventBus: EventBus; + + async start(): Promise {} + async stop(): Promise {} +} +``` + +#### Event-Driven Architecture +Use the `EventBus` for component communication. Events are strongly typed: +```typescript +interface EventBusMap { + deviceMessage: [data: eventdata.DeviceMessage]; + mqttMessage: [data: eventdata.MQTTMessage]; + publishEntityState: [data: eventdata.PublishEntityState]; + // ... other events +} +``` + +#### Dependency Injection +The `Controller` class instantiates and injects dependencies into extensions. Follow this pattern when creating new extensions. + +## Code Style and Conventions + +### Naming Conventions +- **Classes**: PascalCase (e.g., `Extension`, `Device`, `EventBus`) +- **Interfaces/Types**: PascalCase (e.g., `MqttPublishOptions`, `DeviceOptions`) +- **Functions/Methods**: camelCase (e.g., `publishEntityState`, `enableDisableExtension`) +- **Constants**: SCREAMING_SNAKE_CASE for top-level constants (e.g., `CURRENT_VERSION`, `LOG_LEVELS`) +- **Private members**: Prefix with underscore for private class fields only when needed to distinguish from public properties (e.g., `_definitionModelID`) +- **Files**: camelCase for TypeScript files (e.g., `eventBus.ts`, `externalJS.ts`) + +### Import Organization +Follow this import order (separated by blank lines): +1. Node.js built-in modules (use `node:` prefix: `import fs from "node:fs"`) +2. Third-party libraries (e.g., `bind-decorator`, `mqtt`) +3. Type-only imports from external packages (using `type` keyword) +4. Internal absolute imports from project root +5. Type-only imports from internal modules + +Example: +```typescript +import fs from "node:fs"; +import bind from "bind-decorator"; +import type {IClientOptions} from "mqtt"; +import {connectAsync} from "mqtt"; +import type {Zigbee2MQTTAPI} from "./types/api"; +import logger from "./util/logger"; +import * as settings from "./util/settings"; +``` + +### Type Annotations +- Use `type` imports for TypeScript types: `import type * as zhc from "zigbee-herdsman-converters"` +- Explicitly type function parameters and return types +- Use `KeyValue` type for generic object payloads: `type KeyValue = Record` +- Prefer interfaces for object shapes, type aliases for unions/intersections +- Use namespace exports for related types: `export type * as ZSpec from "zigbee-herdsman/dist/zspec"` + +### Async/Await Patterns +- Always use `async/await` for asynchronous operations +- Return types should be explicitly `Promise` +- Methods that don't return values should be `Promise` +- Use `Awaited>` for inferring async function return types + +### Decorators +Use `@bind` decorator from `bind-decorator` for methods that need `this` binding: +```typescript +@bind async onMQTTMessage(data: eventdata.MQTTMessage): Promise { + // Implementation +} +``` + +### Error Handling +- Use `throw new Error("message")` for explicit errors +- Include descriptive error messages +- Log errors using the logger: `logger.error("message")` +- For Zigbee-herdsman errors, log the stack trace: `logger.error((error as Error).stack!)` +- Catch and handle errors at appropriate boundaries (controller level) + +### Logging +Use the centralized logger (winston-based): +```typescript +import logger from "./util/logger"; + +logger.info("message"); +logger.warning("message"); +logger.error("message"); +logger.debug("message"); +``` + +- Use namespaced loggers for specific modules (created internally by logger) +- Log levels: `error`, `warning`, `info`, `debug` (from most to least critical) +- Include relevant context in log messages (device names, IEEE addresses, etc.) + +## Code Quality Standards + +### Maintainability +- Write self-documenting code with clear, descriptive names +- Keep methods focused on single responsibilities +- Abstract classes should define clear contracts with protected members for subclasses +- Use constructor dependency injection for required dependencies +- Limit function complexity - methods should be concise and focused +- Use TypeScript's strict mode features (`noImplicitAny`, `noImplicitThis`) + +### Performance +- Use `rimrafSync` for synchronous file deletion when appropriate +- Leverage async/await for I/O operations to avoid blocking +- Use JSON stable stringify for consistent object serialization: `json-stable-stringify-without-jsonify` +- Cache computed values when appropriate (see device model patterns) +- Use getter methods for computed properties that should be cached + +### Security +- Validate input using Ajv JSON schema validation (see `settings.ts` pattern) +- Sanitize file paths using `path.join` from Node.js +- Use YAML safe loading: `yaml.safeLoad()` +- Handle sensitive data (credentials, tokens) through settings with proper defaults +- Never log sensitive information (passwords, tokens) + +### Testability +- Write tests using Vitest with describe/it/expect patterns +- Mock external dependencies using Vitest's `vi.mock()` +- Use `beforeEach`, `afterEach`, `beforeAll`, `afterAll` for test setup/teardown +- Place test files in `test/` directory with `.test.ts` extension +- Mock constructors and modules in the pattern shown in `test/controller.test.ts` +- Use `flushPromises()` utility for async test synchronization +- Target 100% code coverage (configured in vitest.config.mts) + +## Testing Standards + +### Unit Testing Structure +```typescript +import {afterAll, beforeAll, beforeEach, describe, expect, it, vi} from "vitest"; + +describe("ComponentName", () => { + beforeEach(() => { + // Setup + }); + + it("Should do something specific", async () => { + // Arrange + const input = {}; + + // Act + const result = await someFunction(input); + + // Assert + expect(result).toBe(expected); + }); +}); +``` + +### Mocking Patterns +- Create mock modules in `test/mocks/` directory +- Use `vi.fn()` for function mocks +- Use `vi.mock()` for module mocks +- Clear mocks in `afterEach` or between tests +- Mock external libraries like `mqtt`, `zigbee-herdsman` consistently + +### Test Coverage +- All code in `lib/**` should be covered +- Use coverage reports: `pnpm test:coverage` +- Thresholds set to 100% (can be adjusted per project needs) +- Tests should cover both success and failure paths + +## Documentation Standards + +### JSDoc Comments +Use JSDoc-style comments for classes and public methods: +```typescript +/** + * Besides initializing variables, the constructor should do nothing! + * + * @param {Zigbee} zigbee Zigbee controller + * @param {Mqtt} mqtt MQTT controller + * @param {State} state State controller + * @param {Function} publishEntityState Method to publish device state to MQTT. + * @param {EventBus} eventBus The event bus + */ +constructor(zigbee: Zigbee, mqtt: Mqtt, state: State, ...) { +``` + +### Comment Style +- Use single-line comments (`//`) for implementation notes +- Use JSDoc (`/** */`) for public APIs and class/method documentation +- Include context for non-obvious logic +- Document parameters with their types and purposes +- Use `@param` tags with TypeScript types in braces +- Use biome-ignore comments when necessary: `// biome-ignore lint/rule: reason` + +### Code Documentation +- Document complex algorithms or business logic +- Explain "why" not just "what" when logic is non-trivial +- Include links to relevant issues or documentation when applicable +- Document deprecations and breaking changes + +## TypeScript-Specific Guidelines + +### Module System +- Use ES modules with `import`/`export` syntax +- Default exports for main classes: `export default class Device {}` +- Named exports for utilities and types: `export const LOG_LEVELS = ...` +- Namespace exports for related types: `export type * as ZSpec from ...` +- Use `.js` extension in imports for local modules when using dynamic imports: `await import("./extension/frontend.js")` + +### Type Safety +- Enable all strict type checking options +- Use type guards and assertions when necessary: `asserts expose is zhc.Numeric` +- Prefer `unknown` over `any` when type is truly unknown +- Use `// biome-ignore lint/suspicious/noExplicitAny: API` when `any` is necessary +- Define proper interfaces for external module types (e.g., `unix-dgram.d.ts`) + +### Generic Types +- Use generics for reusable, type-safe abstractions +- Example: `abstract class ExternalJSExtension extends Extension` +- Constrain generics when appropriate +- Document generic type parameters + +### Utility Types +- Use built-in utility types: `Partial`, `Required`, `Pick`, `Omit`, `Record` +- Use `Awaited>` for async function return types +- Define custom utility types when patterns emerge +- Use `type` for aliases, `interface` for object shapes + +## Version Control and Releases + +### Versioning Strategy +- Follow Semantic Versioning (MAJOR.MINOR.PATCH) +- Current version managed in `package.json` +- Use `-dev` suffix for development versions (e.g., `2.6.2-dev`) +- Configuration version tracked separately: `CURRENT_VERSION = 4` + +### Changelog +- Maintain CHANGELOG.md with all changes +- Group changes by type: Bug Fixes, Features, Breaking Changes +- Include issue/PR references: `([#28583](url))` +- Include commit references: `([09f33b3](url))` +- Use conventional commits format + +### Git Workflow +- Development on `dev` branch +- Production releases from `master` branch +- Use meaningful commit messages +- Reference issues in commits + +## Project-Specific Patterns + +### Settings Management +- All configuration loaded through `util/settings.ts` +- Validate settings using Ajv with JSON schema +- Schema defined in `settings.schema.json` +- Support runtime setting changes with restart detection +- Use `settings.get()` to access current configuration +- Use `settings.getDevice(ieeeAddr)` for device-specific config + +### Device and Group Models +- Devices and groups are domain models wrapping `zigbee-herdsman` entities +- Access underlying entity via `.zh` property +- Expose computed properties as getters +- Include definition from `zigbee-herdsman-converters` +- Handle coordinator devices specially (type checking) + +### MQTT Integration +- MQTT client wrapped in `Mqtt` class +- Publish options: `retain`, `qos` properties +- Topics follow pattern: `{base_topic}/{device}/{attribute}` +- Event-based message handling via EventBus +- Clean disconnect handling with retry logic + +### Extension System +- Extensions are loosely coupled plugins +- Lifecycle: constructor → start() → stop() +- Constructor should only assign properties (no side effects) +- Use EventBus for inter-extension communication +- Extensions can be enabled/disabled at runtime +- External extensions loaded from `data/external_extensions/` + +### State Management +- State persisted to `state.json` +- Cached in memory for performance +- Device states include all exposed attributes +- State changes trigger events via EventBus + +## Best Practices Specific to This Project + +1. **Never use language features beyond TypeScript 5.9.3 or ES2024** +2. **Always respect exact versions of zigbee-herdsman and zigbee-herdsman-converters** - these are critical for device compatibility +3. **Use the EventBus for all component communication** - avoid direct coupling +4. **Follow the Extension pattern for new features** - don't add logic directly to Controller +5. **Log appropriately** - info for user-relevant events, debug for developer info, error for failures +6. **Test with real Zigbee scenarios** - many edge cases exist with different device types +7. **Handle coordinator specially** - coordinator is a device but with unique behavior +8. **Validate all external input** - MQTT messages, configuration files, device data +9. **Use the bind decorator** for event handlers to preserve `this` context +10. **Match the exact code formatting** - Biome enforces 4 spaces, 150 line width, no bracket spacing + +## Common Patterns to Follow + +### Creating a New Extension +1. Extend `Extension` abstract class +2. Accept all dependencies in constructor +3. Implement `start()` method for initialization +4. Subscribe to EventBus events in `start()` +5. Implement `stop()` method for cleanup +6. Export as default: `export default class MyExtension extends Extension` + +### Accessing Device Information +```typescript +const device: Device; // Our wrapper +device.ieeeAddr; // IEEE address +device.name; // Friendly name +device.zh; // Underlying zigbee-herdsman device +device.definition; // zigbee-herdsman-converters definition +device.options; // User configuration +``` + +### Publishing MQTT Messages +```typescript +await this.mqtt.publish(topic, message, {retain: true, qos: 0}); +``` + +### Emitting Events +```typescript +this.eventBus.emit('deviceMessage', {device, message}); +``` + +### Listening to Events +```typescript +this.eventBus.on('deviceMessage', this.onDeviceMessage, this); +``` + +## Integration Points + +### Zigbee-Herdsman Integration +- Start controller: `await this.zigbee.start()` +- Access coordinator: `this.zigbee.coordinator()` +- Device operations through `zigbee-herdsman` API +- Event handling through EventBus wrappers + +### MQTT Integration +- Connect: `await this.mqtt.connect()` +- Subscribe: `await this.mqtt.subscribe(topic)` +- Publish: `await this.mqtt.publish(topic, message, options)` +- Handle messages via EventBus `mqttMessage` event + +### Frontend Integration +- Optional extension loaded dynamically +- Serves static files with compression +- WebSocket support for real-time updates +- Configurable port and base URL + +### Home Assistant Integration +- Optional extension for discovery +- Publishes discovery messages to MQTT +- Supports entities, sensors, and devices +- Configurable discovery topic + +## Critical Compatibility Notes + +1. **Node.js**: Only versions 20, 22, and 24 are supported +2. **TypeScript**: Features must be compatible with 5.9.3 +3. **Zigbee Libraries**: Exact versions are critical - do not suggest upgrades without testing +4. **MQTT Protocol**: Uses MQTT 3.1.1 and 5.0 features +5. **ES Modules**: Project uses ESM with NodeNext resolution +6. **Experimental Decorators**: Required for `@bind` decorator support + +## When in Doubt + +1. **Search for similar patterns** in the existing codebase +2. **Check existing extensions** for implementation examples +3. **Follow the controller and extension architecture** - don't bypass it +4. **Consult the test files** for usage examples +5. **Match the exact style** - run `pnpm check` to verify +6. **Prioritize consistency** over external best practices +7. **Test thoroughly** - this project controls real hardware + +## Resources + +- Repository: https://github.com/Koenkk/zigbee2mqtt +- Documentation: https://koenkk.github.io/zigbee2mqtt +- License: GPL-3.0 +- Issue Tracker: https://github.com/Koenkk/zigbee2mqtt/issues diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..b0b515bfc --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,386 @@ +# AGENTS.md + +## Project Overview + +Zigbee2MQTT is a Zigbee to MQTT bridge that allows you to use your Zigbee devices without the vendor's bridge or gateway. It bridges events and allows you to control Zigbee devices via MQTT, integrating them with any smart home infrastructure. + +### Architecture + +- **Language**: TypeScript 5.9.3 compiled to JavaScript (ES modules with NodeNext resolution) +- **Runtime**: Node.js (versions 20, 22, or 24) +- **Package Manager**: pnpm 10.12.1 (strictly enforced via `packageManager` field) +- **Core Dependencies**: + - `zigbee-herdsman` (6.2.0 - exact version, handles Zigbee adapter communication) + - `zigbee-herdsman-converters` (25.42.0 - exact version, device definitions) + - `mqtt` (5.14.1 - MQTT client) + - `winston` (3.18.3 - logging) + +### Project Structure + +``` +lib/ # TypeScript source code +├── controller.ts # Main controller orchestrating components +├── mqtt.ts # MQTT client management +├── zigbee.ts # Zigbee network management +├── state.ts # State management +├── eventBus.ts # Event-driven communication +├── extension/ # Extension system (plugins) +│ └── extension.ts # Abstract base class +├── model/ # Domain models (Device, Group) +├── util/ # Utility functions +└── types/ # TypeScript type definitions +test/ # Vitest test files with mocks +data/ # Runtime configuration and database +dist/ # Compiled JavaScript output +``` + +## Setup Commands + +### Prerequisites + +- Node.js version 20, 22, or 24 +- pnpm 10.12.1 (will be auto-installed via corepack if not present) + +### Installation + +```bash +# Install dependencies (uses pnpm lockfile) +pnpm install --frozen-lockfile + +# For development without lockfile restrictions +pnpm install +``` + +### Initial Build + +```bash +# Full build (TypeScript compilation + hash generation) +pnpm run build + +# Build type definitions only +pnpm run build:types +``` + +## Development Workflow + +### Starting Development + +```bash +# Watch mode - recompile on file changes +pnpm run build:watch + +# In another terminal, start Zigbee2MQTT +pnpm start +``` + +### Code Quality Checks + +```bash +# Run Biome linter and formatter (check only) +pnpm run check + +# Auto-fix linting and formatting issues +pnpm run check:w + +# The check runs with --error-on-warnings flag +# Configuration: biome.json (4-space indent, 150 line width, no bracket spacing) +``` + +### Clean Build + +```bash +# Remove build artifacts +pnpm run clean + +# Removes: coverage/, dist/, tsconfig.tsbuildinfo +``` + +## Testing Instructions + +### Running Tests + +```bash +# Run all tests once +pnpm test + +# Run tests with coverage report +pnpm run test:coverage + +# Watch mode - re-run tests on changes +pnpm run test:watch + +# Run benchmarks +pnpm run bench +``` + +### Test Requirements + +- **Coverage**: 100% code coverage is enforced (configured in `test/vitest.config.mts`) +- **Framework**: Vitest 3.1.1 with @vitest/coverage-v8 +- **Test Files**: Located in `test/` directory with `.test.ts` extension +- **Mocks**: Centralized in `test/mocks/` directory +- **Coverage Report**: Generated in `coverage/` directory (HTML report at `coverage/index.html`) + +### Running Specific Tests + +```bash +# Run tests matching a pattern +pnpm vitest run -t "test name pattern" --config ./test/vitest.config.mts + +# Run specific test file +pnpm vitest run test/controller.test.ts --config ./test/vitest.config.mts + +# Focus on one test area in watch mode +pnpm vitest watch -t "Extension" --config ./test/vitest.config.mts +``` + +## Code Style Guidelines + +### TypeScript Conventions + +- **Module System**: ES modules with NodeNext resolution +- **Target**: ESNext +- **Strict Mode**: Enabled (`noImplicitAny`, `noImplicitThis`) +- **Decorators**: Experimental decorators enabled (used for `@bind` from `bind-decorator`) + +### Import Order + +1. Node.js built-in modules (with `node:` prefix) +2. Third-party libraries +3. Type-only imports from external packages (using `type` keyword) +4. Internal absolute imports +5. Type-only imports from internal modules + +Example: +```typescript +import fs from "node:fs"; +import bind from "bind-decorator"; +import type {IClientOptions} from "mqtt"; +import {connectAsync} from "mqtt"; +import type {Zigbee2MQTTAPI} from "./types/api"; +import logger from "./util/logger"; +``` + +### Naming Conventions + +- **Classes**: PascalCase (e.g., `Extension`, `Device`) +- **Functions/Methods**: camelCase (e.g., `publishEntityState`) +- **Constants**: SCREAMING_SNAKE_CASE (e.g., `CURRENT_VERSION`) +- **Interfaces/Types**: PascalCase (e.g., `MqttPublishOptions`) +- **Files**: camelCase for TypeScript (e.g., `eventBus.ts`) + +### Code Patterns + +- **Async/Await**: Always use async/await, explicitly type return as `Promise` +- **Error Handling**: Use `throw new Error("message")`, log with winston logger +- **Event Handlers**: Use `@bind` decorator to preserve `this` context +- **Logging**: Use `logger.info()`, `logger.warning()`, `logger.error()`, `logger.debug()` + +### Formatting Rules (Biome) + +- 4-space indentation +- 150 character line width +- No bracket spacing in objects +- Run `pnpm run check:w` to auto-format + +## Build and Deployment + +### Build Process + +```bash +# Production build +pnpm run build + +# Outputs: +# - Compiled JavaScript in dist/ +# - Type definitions in dist/types/ +# - Includes hash generation for version tracking +``` + +### Pre-publish + +```bash +# Automatically runs before publishing +pnpm run prepack + +# Performs: clean + build +``` + +### Environment Setup + +- Configuration stored in `data/configuration.yaml` +- Database in `data/database.db` +- Logs in `data/log/` +- External extensions in `data/external_extensions/` +- External converters in `data/external_converters/` + +## Architecture Patterns + +### Extension System + +All features are implemented as extensions that inherit from the abstract `Extension` base class: + +```typescript +abstract class Extension { + protected zigbee: Zigbee; + protected mqtt: Mqtt; + protected state: State; + protected publishEntityState: PublishEntityState; + protected eventBus: EventBus; + + async start(): Promise {} // Initialize extension + async stop(): Promise {} // Cleanup extension +} +``` + +**Key Points**: +- Constructor should only assign properties (no side effects) +- Initialization happens in `start()` method +- Use EventBus for inter-component communication +- Extensions are loaded and managed by the Controller + +### Event-Driven Communication + +Components communicate via the strongly-typed EventBus: + +```typescript +// Emit events +this.eventBus.emit('deviceMessage', {device, message}); + +// Listen to events +this.eventBus.on('deviceMessage', this.onDeviceMessage, this); +``` + +### Dependency Injection + +The Controller instantiates and injects dependencies into all extensions. Follow this pattern when creating new extensions. + +## Pull Request Guidelines + +### Target Branch + +- **Always create PRs against the `dev` branch** +- The `master` branch is for production releases only + +### Before Submitting + +```bash +# Run all checks +pnpm run check +pnpm test + +# Ensure 100% code coverage +pnpm run test:coverage + +# Build successfully +pnpm run build +``` + +### PR Requirements + +- All CI checks must pass (linting, tests, build) +- 100% test coverage maintained +- Code follows Biome formatting rules +- Commit messages should be descriptive +- Reference related issues when applicable + +### CI Pipeline + +The GitHub Actions CI workflow (`.github/workflows/ci.yml`) runs: +1. Biome code quality checks (`pnpm run check`) +2. TypeScript compilation (`pnpm run build`) +3. Full test suite with coverage (`pnpm run test:coverage`) +4. Benchmarks (on dev branch and PRs) +5. Docker image builds (on dev branch and tags) + +## Working with Device Support + +### Adding New Devices + +**Important**: Device support is NOT added to this repository. All device definitions live in `zigbee-herdsman-converters`. + +- Follow the guide at: https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html +- No changes to zigbee2mqtt codebase are needed for new devices +- Device definitions are automatically picked up from `zigbee-herdsman-converters` + +## Debugging and Troubleshooting + +### Development Setup + +For the easiest development experience, set up a bare-metal installation following: +https://www.zigbee2mqtt.io/guide/installation/01_linux.html + +### Logging + +- Winston logger is initialized in `lib/util/logger.ts` +- Log levels: `error`, `warning`, `info`, `debug` +- Logs are written to console and/or file based on configuration +- Use structured logging with context (device names, IEEE addresses) + +### Common Issues + +1. **Import errors after file moves**: Run `pnpm run check` to verify TypeScript and ESLint +2. **Test failures**: Check if mocks in `test/mocks/` need updates +3. **Build errors**: Ensure Node.js version is 20, 22, or 24 +4. **Coverage issues**: View HTML report at `coverage/index.html` to identify uncovered code + +### Performance Considerations + +- Use `rimrafSync` for synchronous file operations +- Leverage async/await to avoid blocking +- Cache computed values in getters when appropriate +- EventBus provides loose coupling between components + +## Critical Version Requirements + +### Exact Versions + +These dependencies use **exact versions** (no semver ranges) - do not upgrade without thorough testing: + +- `zigbee-herdsman@6.2.0` - Critical for Zigbee protocol compatibility +- `zigbee-herdsman-converters@25.42.0` - Device definitions must match herdsman version + +### Node.js Compatibility + +Only these Node.js versions are supported: +- Node.js 20.x +- Node.js 22.x +- Node.js 24.x + +Using other versions may cause runtime errors or incompatibilities. + +## Additional Notes + +### Package Manager + +This project **requires pnpm 10.12.1**. The `packageManager` field in package.json enforces this via Corepack. + +Do not use npm or yarn - they will not respect the pnpm-specific configuration. + +### TypeScript Compilation + +- Source files in `lib/` are compiled to `dist/` +- Type definitions exported from `dist/types/api.d.ts` +- Source maps are inlined for debugging +- Uses composite project references for faster incremental builds + +### External Extensions + +To load external extensions: +1. Place JavaScript files in `data/external_extensions/` +2. They will be automatically loaded on startup +3. No configuration changes needed + +### Code Quality Tools + +- **Linting/Formatting**: Biome 2.2.5 (replaces ESLint + Prettier) +- **Type Checking**: TypeScript 5.9.3 +- **Testing**: Vitest 3.1.1 +- **Coverage**: @vitest/coverage-v8 + +### Documentation + +- Main documentation: https://www.zigbee2mqtt.io/ +- Contributing guide: `CONTRIBUTING.md` +- Coding standards: `.github/copilot-instructions.md` +- Issue tracker: https://github.com/Koenkk/zigbee2mqtt/issues