# Contributing to Superdav AI Agent

Thank you for your interest in contributing! This guide covers everything you need to get started: local environment setup, running the test suite and linters, commit conventions, and the PR workflow.

## Table of Contents

- [Prerequisites](#prerequisites)
- [Local Development Setup](#local-development-setup)
- [Project Structure](#project-structure)
- [Running the Test Suite](#running-the-test-suite)
- [Code Quality Tools](#code-quality-tools)
- [Commit Conventions](#commit-conventions)
- [PR Workflow](#pr-workflow)
- [Testing Requirements](#testing-requirements)
- [Code Style Reference](#code-style-reference)
- [WordPress.org Plugin Directory](#wordpressorg-plugin-directory)

---

## Prerequisites

| Tool | Minimum version | Notes |
|------|----------------|-------|
| PHP | 8.2 | Required for strict types and enums |
| Composer | 2.x | Dependency manager |
| Node.js | 20.x | LTS recommended |
| npm | 10.x | Bundled with Node 20 |
| Docker | 24.x | Required for wp-env test environment |
| Git | 2.x | |

Install Docker Desktop (macOS/Windows) or Docker Engine (Linux) and ensure the daemon is running before starting the test environment.

---

## Local Development Setup

### 1. Clone and install dependencies

```bash
git clone https://github.com/Ultimate-Multisite/ai-agent.git
cd ai-agent

# Install PHP dependencies (includes PHPUnit, PHPCS, PHPStan)
composer install

# Install Node dependencies (includes wp-env, ESLint, Stylelint, wp-scripts)
npm install
```

### 2. Start the development environment

```bash
# Build JS assets in watch mode (rebuilds on file change)
npm start
```

The built assets are written to `build/`. The plugin is ready to activate in any WordPress installation that has the `build/` directory present.

### 3. Start the wp-env WordPress environment (optional, for manual testing)

```bash
# First run pulls Docker images — takes a few minutes
npm run wp-env:start
```

This starts two WordPress instances:
- **Development** at `http://localhost:8888` — for manual testing
- **Tests** at `http://localhost:8889` — used by PHPUnit

Both run WordPress 6.9 in multisite mode (path-based, not subdomain) with `WP_DEBUG` enabled. The plugin is mounted at `wp-content/plugins/ai-agent` in both containers.

Stop the environment when you are done:

```bash
npm run wp-env:stop
```

To reset the environment to a clean state (drops all data):

```bash
npm run wp-env:clean
```

---

## Project Structure

```
ai-agent/
├── ai-agent.php          # Plugin entry point
├── includes/
│   ├── Core/             # Database, Settings, AgentLoop
│   ├── Models/           # Memory, Skill, Chunker
│   ├── Abilities/        # WordPress Abilities API implementations
│   ├── Knowledge/        # Knowledge base system
│   ├── Tools/            # Custom tools and profiles
│   ├── Automations/      # Scheduled and event-driven automations
│   ├── REST/             # REST API controller
│   ├── Admin/            # Admin pages and widgets
│   ├── CLI/              # WP-CLI commands
│   └── Enums/            # PHP 8.1+ enums
├── src/
│   ├── components/       # Shared React components
│   ├── store/            # @wordpress/data Redux store
│   ├── admin-page/       # Admin page entry point
│   ├── floating-widget/  # Floating chat widget entry point
│   └── settings-page/    # Settings page entry point
├── tests/
│   ├── AiAgent/          # PHPUnit test classes
│   ├── bootstrap.php     # PHPUnit bootstrap
│   └── mu-plugins/       # Must-use plugins loaded in test environment
├── build/                # Compiled JS/CSS (git-ignored, generated by npm)
├── .wp-env.json          # wp-env environment configuration
├── phpcs.xml             # PHP_CodeSniffer ruleset
├── phpstan.neon          # PHPStan configuration
└── phpunit.xml.dist      # PHPUnit configuration
```

---

## Running the Test Suite

### PHPUnit (PHP unit tests)

Tests run inside the `tests-wordpress` Docker container via wp-env. Docker must be running.

```bash
# Start the test environment (required before running tests)
npm run wp-env:start

# Run the full test suite
npm run test:php

# Run with human-readable testdox output
npm run test:php:testdox

# Run with code coverage report (stdout summary + HTML in coverage-html/)
npm run test:php:coverage

# Stop the environment when done
npm run wp-env:stop
```

The test environment is configured in `.wp-env.json`:
- WordPress 6.9, PHP 8.2
- Multisite enabled (path-based)
- `WP_DEBUG` and `SCRIPT_DEBUG` enabled
- Must-use plugins from `tests/mu-plugins/` loaded automatically

PHPUnit configuration is in `phpunit.xml.dist`. Test files live in `tests/AiAgent/` and must be named `*Test.php`.

**Writing tests:**

```php
<?php

declare(strict_types=1);

namespace AiAgent\Tests;

use WP_UnitTestCase;

class MyFeatureTest extends WP_UnitTestCase {

    public function test_something_works(): void {
        // Arrange
        $expected = 'value';

        // Act
        $result = my_function();

        // Assert
        $this->assertSame( $expected, $result );
    }
}
```

Use `WP_UnitTestCase` (not plain `PHPUnit\Framework\TestCase`) to get WordPress test helpers, factory methods, and automatic database rollback between tests.

---

## Code Quality Tools

All quality checks run automatically in CI on every push and PR. Run them locally before pushing to catch issues early.

### Run all linters at once

```bash
# PHP (PHPCS + PHPStan) + JS (ESLint) + CSS (Stylelint)
npm run lint
```

### PHP CodeSniffer (PHPCS)

Enforces WordPress Coding Standards with PSR-4 naming and PHP 8.2 compatibility.

```bash
# Check for violations
npm run lint:php
# or directly:
vendor/bin/phpcs

# Auto-fix fixable violations
npm run lint:php:fix
# or directly:
vendor/bin/phpcbf
```

Configuration: `phpcs.xml`. Key rules in effect:
- WordPress Coding Standards (with PSR-4 naming exceptions)
- Output escaping enforced (`WordPress.Security.EscapeOutput`)
- Nonce verification enforced (`WordPress.Security.NonceVerification`)
- PHP 8.2+ compatibility via `PHPCompatibilityWP`
- Text domain must be `superdav-ai-agent`

### PHPStan (static analysis)

Runs at level 5 against `includes/` and `ai-agent.php`.

```bash
vendor/bin/phpstan analyse
# or via composer:
composer phpstan
```

Configuration: `phpstan.neon`. PHPStan runs without wp-env — it uses stubs from `szepeviktor/phpstan-wordpress`.

### ESLint (JavaScript)

Lints `src/` using `@wordpress/eslint-plugin` rules.

```bash
# Check for violations
npm run lint:js

# Auto-fix fixable violations
npm run lint:js:fix
```

### Stylelint (CSS)

Lints all `src/**/*.css` files using `@wordpress/stylelint-config`.

```bash
# Check for violations
npm run lint:css

# Auto-fix fixable violations
npm run lint:css:fix
```

### Build check

Verify the JS/CSS build compiles without errors:

```bash
npm run build
```

---

## Commit Conventions

We use [Conventional Commits](https://www.conventionalcommits.org/). Every commit message must follow this format:

```
<type>: <short description>

[optional body]

[optional footer: Closes #NNN]
```

**Types:**

| Type | When to use |
|------|-------------|
| `feat:` | New feature or capability |
| `fix:` | Bug fix |
| `docs:` | Documentation only (no code change) |
| `refactor:` | Code restructuring with no behaviour change |
| `chore:` | Maintenance, dependency updates, config changes |
| `perf:` | Performance improvement |
| `test:` | Adding or updating tests |
| `ci:` | CI/CD workflow changes |

**Examples:**

```bash
git commit -m "feat: add memory search by category"
git commit -m "fix: prevent duplicate session creation on concurrent requests"
git commit -m "docs: expand PHPUnit setup instructions in CONTRIBUTING"
git commit -m "refactor: extract prompt builder into dedicated class"
git commit -m "chore: bump @wordpress/scripts to 30.x"
```

**Rules:**
- Use the imperative mood: "add feature" not "added feature"
- Keep the subject line under 72 characters
- Reference issues in the footer: `Closes #161`
- Husky runs a commit-msg hook that validates the format — commits that don't match will be rejected

---

## PR Workflow

### 1. Fork and branch

```bash
# Fork on GitHub, then clone your fork
git clone https://github.com/YOUR_USERNAME/ai-agent.git
cd ai-agent

# Add the upstream remote
git remote add upstream https://github.com/Ultimate-Multisite/ai-agent.git

# Create a branch from main
git checkout -b feat/my-feature
```

Branch naming convention: `<type>/<short-description>` — e.g., `feat/memory-search`, `fix/session-timeout`, `docs/contributing`.

### 2. Make your changes

- Follow the [Code Style Reference](#code-style-reference) below
- Add or update tests for any behaviour change (see [Testing Requirements](#testing-requirements))
- Run linters locally before pushing: `npm run lint`
- Run the test suite: `npm run wp-env:start && npm run test:php`

### 3. Push and open a PR

```bash
git push origin feat/my-feature
```

Open a PR against `main` on the upstream repository. In the PR description:

- **Summarise what changed and why** — not just what files were touched
- **Link the related issue**: `Closes #NNN` (this auto-closes the issue on merge)
- **Describe how you tested it** — manual steps, test commands run, or new test names

### 4. CI checks

All PRs must pass:

| Check | Command | Config |
|-------|---------|--------|
| PHPUnit | `npm run test:php` | `phpunit.xml.dist` |
| PHPCS | `vendor/bin/phpcs` | `phpcs.xml` |
| PHPStan | `vendor/bin/phpstan analyse` | `phpstan.neon` |
| ESLint | `npx eslint src/` | `.eslintrc` / `@wordpress/eslint-plugin` |
| Stylelint | `npx stylelint "src/**/*.css"` | `@wordpress/stylelint-config` |
| Build | `npm run build` | `webpack.config.js` via `@wordpress/scripts` |

CI runs on GitHub Actions (`.github/workflows/tests.yml` and `.github/workflows/code-quality.yml`). Fix any failures before requesting review.

### 5. Review and merge

- A maintainer will review your PR
- Address review comments with new commits (do not force-push after review has started)
- Once approved and CI is green, a maintainer will merge

---

## Testing Requirements

### When tests are required

| Change type | Tests required |
|-------------|---------------|
| New PHP class or method | Yes — unit test covering the public API |
| Bug fix | Yes — regression test that would have caught the bug |
| REST API endpoint change | Yes — test the endpoint response and error cases |
| Database schema change | Yes — test migration and data integrity |
| Refactor (no behaviour change) | No — but existing tests must still pass |
| Documentation only | No |
| CSS/JS styling change | No (unless it affects JS logic) |

### Test file location and naming

- Test files go in `tests/AiAgent/`
- File name: `{ClassName}Test.php` matching the class under test
- Class name: `{ClassName}Test` in namespace `AiAgent\Tests`

### What to test

- **Happy path**: the expected behaviour with valid inputs
- **Error cases**: invalid inputs, missing data, permission failures
- **Edge cases**: empty strings, zero values, maximum lengths
- **WordPress integration**: hooks fired, options saved, database rows created

### Test helpers

`WP_UnitTestCase` provides:
- `$this->factory->user->create()` — create test users
- `$this->factory->post->create()` — create test posts
- `$this->factory->blog->create()` — create test subsites (multisite)
- Automatic database rollback after each test method

---

## Code Style Reference

### PHP

- **Namespace**: PSR-4 under `AiAgent\` (e.g., `namespace AiAgent\Core;`)
- **File naming**: `{ClassName}.php` — must match the class name exactly
- **Strict types**: every file must start with `declare(strict_types=1);`
- **Type declarations**: required on all parameters and return types
- **Error handling**: return `WP_Error` objects; never throw exceptions in hook callbacks
- **Hooks**: `add_action()` / `add_filter()` with priority 10 by default
- **i18n**: wrap all user-facing strings in `__( 'text', 'superdav-ai-agent' )`
- **Output escaping**: always escape output — `esc_html()`, `esc_attr()`, `esc_url()`, `wp_kses_post()`
- **Nonces**: verify nonces before processing any form submission

```php
<?php

declare(strict_types=1);

namespace AiAgent\Core;

class MyClass {

    private string $name;

    public function __construct( string $name ) {
        $this->name = $name;
    }

    public function getName(): string {
        return $this->name;
    }
}
```

### JavaScript / React

- **Framework**: React 18 with `@wordpress/element` and `@wordpress/components`
- **State**: `@wordpress/data` Redux store — use `useSelect` / `useDispatch`
- **Imports**: WordPress packages first, then internal
- **i18n**: `__( 'text', 'superdav-ai-agent' )` from `@wordpress/i18n`
- **Components**: PascalCase filenames and component names

```js
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { Button } from '@wordpress/components';

export function MyComponent() {
    const value = useSelect( ( select ) =>
        select( 'sd-ai-agent' ).getValue()
    );

    return (
        <Button variant="primary">
            { __( 'Click me', 'superdav-ai-agent' ) }
        </Button>
    );
}
```

### CSS

- One `style.css` per component, co-located with the component file
- Use CSS custom properties for colours and spacing
- Follow `@wordpress/stylelint-config` rules (BEM-like selectors, no IDs)

---

## WordPress.org Plugin Directory

The plugin is distributed through the [WordPress.org plugin directory](https://wordpress.org/plugins/sd-ai-agent/).
Releases are published via SVN after passing the WP.org review process.

For the complete submission and release workflow — including the initial review
submission, SVN checkout, trunk deployment, and version tagging — see
[docs/wordpress-org-submission.md](docs/wordpress-org-submission.md).

### Quick reference: releasing a new version

```bash
# 1. Update Version: in sd-ai-agent.php and Stable tag: in readme.txt
# 2. Add changelog entry to readme.txt

# 3. Deploy to WP.org SVN (requires prior SVN checkout)
bin/deploy-wporg.sh --version X.Y.Z --username YOUR_WP_USERNAME
```

See `bin/deploy-wporg.sh --help` for all options, including `--dry-run`.

---

## Getting Help

- Open a [GitHub Discussion](https://github.com/Ultimate-Multisite/ai-agent/discussions) for questions
- Open an [issue](https://github.com/Ultimate-Multisite/ai-agent/issues) for bugs or feature requests
- See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for community guidelines
