Add 5 pi extensions: pi-subagents, pi-crew, rpiv-pi, pi-interactive-shell, pi-intercom

This commit is contained in:
2026-05-08 15:59:25 +10:00
parent d0d1d9b045
commit 31b4110c87
457 changed files with 85157 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
# CLAUDE.md
ASP.NET Core 8 Web API with Clean Architecture (CQRS + MediatR).
## Project map
- `src/Api/` - ASP.NET Core controllers, middleware, DI setup
- `src/Application/` - MediatR handlers, validators, DTOs
- `src/Domain/` - Entities, value objects, domain events
- `src/Infrastructure/` - EF Core, external services, file storage
- `tests/` - Unit and integration tests
## Commands
| Command | What it does |
|---|---|
| `dotnet build` | Build solution |
| `dotnet test` | Run all tests |
| `dotnet run --project src/Api` | Start API locally |
| `dotnet ef migrations add <Name> -p src/Infrastructure` | Create EF migration |
| `dotnet ef database update -p src/Infrastructure` | Apply migrations |
<important if="you are adding a new API endpoint">
- Add controller in `Api/Controllers/` inheriting `BaseApiController`
- Add command/query + handler + validator in `Application/Features/`
- See `Application/Features/Orders/Commands/CreateOrder/` for the pattern
</important>
<important if="you are adding or modifying EF Core migrations or database schema">
- Entities configured via `IEntityTypeConfiguration<T>` in `Infrastructure/Persistence/Configurations/`
- Always create a migration after schema changes — never modify existing migrations
</important>
<important if="you are writing or modifying tests">
- Unit tests: xUnit + NSubstitute, one test class per handler
- Integration tests: `WebApplicationFactory<Program>` with test database
- See `tests/Application.IntegrationTests/TestBase.cs` for setup
</important>

View File

@@ -0,0 +1,42 @@
# CLAUDE.md
Express API + React frontend in a Turborepo monorepo.
## Project map
- `apps/api/` - Express REST API
- `apps/web/` - React SPA
- `packages/db/` - Prisma schema and client
- `packages/ui/` - Shared component library
- `packages/config/` - Shared configuration
## Commands
| Command | What it does |
|---|---|
| `turbo build` | Build all packages |
| `turbo test` | Run all tests |
| `turbo lint` | Lint all packages |
| `turbo dev` | Start dev server |
| `turbo db:generate` | Regenerate Prisma client after schema changes |
| `turbo db:migrate` | Run database migrations |
<important if="you are adding or modifying API routes">
- All routes go in `apps/api/src/routes/`
- Use Zod for request validation — see `apps/api/src/routes/connections.ts` for the pattern
- Error responses follow RFC 7807 format
- Authentication via JWT middleware
</important>
<important if="you are writing or modifying tests">
- API: Jest + Supertest, Frontend: Vitest + Testing Library
- Test fixtures in `__fixtures__/` directories
- Use `createTestClient()` helper for API integration tests
- Mock database with `prismaMock` from `packages/db/test`
</important>
<important if="you are working with client-side state, stores, or data fetching">
- Zustand for global client state
- React Query for server state
- URL state via `nuqs`
</important>

View File

@@ -0,0 +1,81 @@
# Database Layer Architecture
## Responsibility
SQLite persistence with better-sqlite3, repository pattern (plain types), QueryQueue concurrency, type transformations.
## Dependencies
- **better-sqlite3**: Native SQLite (requires rebuild for Electron)
- **@redis-ui/core**: Domain types
- **p-queue**: Query serialization
## Consumers
- **@redis-ui/services**: Repositories via RepositoryFactory
- **Main process**: DatabaseManager initialization
## Module Structure
```
src/
├── DatabaseManager.ts, QueryQueue.ts # Singleton, concurrency
├── BaseRepository.ts, RepositoryFactory.ts
├── schema.ts
└── repositories/ # One repo per entity
```
## Repository Boundary (CRITICAL: Plain Types, NOT Result<T>)
```typescript
export class ConnectionRepository extends BaseRepository<ConnectionDB, Connection, ConnectionId> {
protected toApplication(db: ConnectionDB): Connection {
return {
id: ConnectionId.create(db.id),
host: db.host,
port: db.port,
sslEnabled: Boolean(db.ssl_enabled), // DB int → boolean
createdAt: new Date(db.created_at), // timestamp → Date
};
}
async findById(id: ConnectionId): Promise<Connection | null> {
return this.queue.enqueueRead((db) => {
const row = db.prepare('SELECT * FROM connections WHERE id = ?').get(id);
return row ? this.toApplication(row) : null;
});
}
}
// Service: Wraps repository in Result<T>
async createConnection(input: CreateInput): Promise<Result<Connection>> {
try {
const connection = await this.connectionRepo.create(input);
return Result.ok(connection);
} catch (error) {
return Result.fail(new InfrastructureError(error.message));
}
}
```
## QueryQueue Pattern (Write Serialization)
```typescript
export class QueryQueue {
private writeQueue = new PQueue({ concurrency: 1 }) // Single writer
private readQueue = new PQueue({ concurrency: 5 }) // Multiple readers
async enqueueWrite<T>(op: (db: Database) => T): Promise<T> {
return this.writeQueue.add(() => op(this.db))
}
}
```
## Architectural Boundaries
- **NO Result<T> in repos**: Services wrap with Result
- **NO unqueued DB ops**: Always use QueryQueue
- **NO raw SQL in services**: Use repositories
<important if="you are adding a new repository to this layer">
## Adding a New Repository
1. Create `XRepository.ts` extending `BaseRepository<XDB, X, XId>`
2. Implement `toApplication()` and `toDatabase()` type mappers
3. Register in `RepositoryFactory`
4. Add table schema in `schema.ts`
</important>

View File

@@ -0,0 +1,64 @@
# Application Layer (CQRS + MediatR)
## Responsibility
Command/query handlers orchestrating domain logic via MediatR pipeline. Sits between API controllers and Domain layer.
## Dependencies
- **MediatR**: Command/query dispatch
- **FluentValidation**: Request validation via pipeline behavior
- **AutoMapper**: Domain ↔ DTO mapping
## Consumers
- **API Controllers**: Send commands/queries via `IMediator`
- **Integration tests**: Direct handler invocation
## Module Structure
```
Application/
├── Common/
│ ├── Behaviors/ # MediatR pipeline (validation, logging)
│ └── Mappings/ # AutoMapper profiles
├── Features/ # One folder per aggregate
│ └── Orders/
│ ├── Commands/ # CreateOrder/, UpdateOrder/ (handler + validator + DTO)
│ └── Queries/ # GetOrder/, ListOrders/
└── DependencyInjection.cs # Service registration
```
## Handler Pattern (Command with Validation)
```csharp
public record CreateOrderCommand(string CustomerId, List<LineItemDto> Items)
: IRequest<Result<OrderDto>>;
public class CreateOrderValidator : AbstractValidator<CreateOrderCommand> {
public CreateOrderValidator(IOrderRepository repo) {
RuleFor(x => x.CustomerId).NotEmpty();
RuleFor(x => x.Items).NotEmpty();
}
}
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, Result<OrderDto>> {
public async Task<Result<OrderDto>> Handle(
CreateOrderCommand request, CancellationToken ct) {
var order = Order.Create(request.CustomerId, request.Items); // Domain factory
await _repo.AddAsync(order, ct);
await _unitOfWork.SaveChangesAsync(ct);
return Result.Ok(_mapper.Map<OrderDto>(order));
}
}
```
## Architectural Boundaries
- **NO domain logic in handlers**: Handlers orchestrate, domain objects contain logic
- **NO direct DbContext access**: Use repository abstractions
- **NO cross-feature references**: Features are independent vertical slices
<important if="you are adding a new feature or command/query handler">
## Adding a New Feature
1. Create folder under `Features/{Aggregate}/{Commands|Queries}/`
2. Add `Command`/`Query` record implementing `IRequest<Result<TDto>>`
3. Add `Validator` extending `AbstractValidator<TCommand>`
4. Add `Handler` implementing `IRequestHandler<TCommand, Result<TDto>>`
5. Add AutoMapper profile in `Common/Mappings/` if new DTO
</important>

View File

@@ -0,0 +1,50 @@
# Schemas Layer Architecture
## Responsibility
Zod validation schemas for dual-layer validation (preload UX + main security), type inference via z.infer<>.
## Dependencies
- **zod**: Runtime validation
## Consumers
- **@redis-ui/ipc**: Main process validation (security)
- **Preload**: Fail-fast validation (UX)
- **TypeScript**: Type inference
## Module Structure
```
src/
├── connection.ts, backup.ts # Domain schemas
└── __tests__/ # Validation tests
```
## Complete Schema Pattern (Types + Validation + Composition)
```typescript
export const createConnectionSchema = z.object({
name: z.string().min(1).max(255),
host: z.string().min(1),
port: z.number().int().min(1).max(65535),
password: z.string().optional(),
database: z.number().int().min(0).max(15).default(0),
})
// Type inference
export type CreateConnectionInput = z.infer<typeof createConnectionSchema>
// Update schema (partial + ID required)
export const updateConnectionSchema = createConnectionSchema.partial().extend({
id: z.string().min(1)
})
```
## Dual-Validation Flow
```
Renderer input → Preload (Zod parse, fail fast) → IPC → Main (Zod parse again, security)
```
## Architectural Boundaries
- **NO any types**: Use z.unknown()
- **NO skipping validation**: Always validate at boundaries
- **NO business logic**: Structure validation only