agent-bober 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +9 -0
- package/LICENSE +21 -0
- package/README.md +495 -0
- package/agents/bober-evaluator.md +323 -0
- package/agents/bober-generator.md +245 -0
- package/agents/bober-planner.md +248 -0
- package/dist/cli/commands/eval.d.ts +6 -0
- package/dist/cli/commands/eval.d.ts.map +1 -0
- package/dist/cli/commands/eval.js +129 -0
- package/dist/cli/commands/eval.js.map +1 -0
- package/dist/cli/commands/init.d.ts +5 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +547 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/plan.d.ts +5 -0
- package/dist/cli/commands/plan.d.ts.map +1 -0
- package/dist/cli/commands/plan.js +87 -0
- package/dist/cli/commands/plan.js.map +1 -0
- package/dist/cli/commands/run.d.ts +5 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +120 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/sprint.d.ts +6 -0
- package/dist/cli/commands/sprint.d.ts.map +1 -0
- package/dist/cli/commands/sprint.js +206 -0
- package/dist/cli/commands/sprint.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +124 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/defaults.d.ts +15 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +226 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +8 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +18 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +189 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +904 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +181 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/contracts/eval-result.d.ts +205 -0
- package/dist/contracts/eval-result.d.ts.map +1 -0
- package/dist/contracts/eval-result.js +87 -0
- package/dist/contracts/eval-result.js.map +1 -0
- package/dist/contracts/index.d.ts +4 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +16 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/contracts/spec.d.ts +101 -0
- package/dist/contracts/spec.d.ts.map +1 -0
- package/dist/contracts/spec.js +51 -0
- package/dist/contracts/spec.js.map +1 -0
- package/dist/contracts/sprint-contract.d.ts +141 -0
- package/dist/contracts/sprint-contract.d.ts.map +1 -0
- package/dist/contracts/sprint-contract.js +80 -0
- package/dist/contracts/sprint-contract.js.map +1 -0
- package/dist/evaluators/builtin/api-check.d.ts +13 -0
- package/dist/evaluators/builtin/api-check.d.ts.map +1 -0
- package/dist/evaluators/builtin/api-check.js +152 -0
- package/dist/evaluators/builtin/api-check.js.map +1 -0
- package/dist/evaluators/builtin/build-check.d.ts +17 -0
- package/dist/evaluators/builtin/build-check.d.ts.map +1 -0
- package/dist/evaluators/builtin/build-check.js +155 -0
- package/dist/evaluators/builtin/build-check.js.map +1 -0
- package/dist/evaluators/builtin/command-runner.d.ts +26 -0
- package/dist/evaluators/builtin/command-runner.d.ts.map +1 -0
- package/dist/evaluators/builtin/command-runner.js +114 -0
- package/dist/evaluators/builtin/command-runner.js.map +1 -0
- package/dist/evaluators/builtin/lint.d.ts +17 -0
- package/dist/evaluators/builtin/lint.d.ts.map +1 -0
- package/dist/evaluators/builtin/lint.js +264 -0
- package/dist/evaluators/builtin/lint.js.map +1 -0
- package/dist/evaluators/builtin/playwright.d.ts +16 -0
- package/dist/evaluators/builtin/playwright.d.ts.map +1 -0
- package/dist/evaluators/builtin/playwright.js +238 -0
- package/dist/evaluators/builtin/playwright.js.map +1 -0
- package/dist/evaluators/builtin/typescript-check.d.ts +12 -0
- package/dist/evaluators/builtin/typescript-check.d.ts.map +1 -0
- package/dist/evaluators/builtin/typescript-check.js +155 -0
- package/dist/evaluators/builtin/typescript-check.js.map +1 -0
- package/dist/evaluators/builtin/unit-test.d.ts +18 -0
- package/dist/evaluators/builtin/unit-test.d.ts.map +1 -0
- package/dist/evaluators/builtin/unit-test.js +279 -0
- package/dist/evaluators/builtin/unit-test.js.map +1 -0
- package/dist/evaluators/index.d.ts +11 -0
- package/dist/evaluators/index.d.ts.map +1 -0
- package/dist/evaluators/index.js +13 -0
- package/dist/evaluators/index.js.map +1 -0
- package/dist/evaluators/plugin-interface.d.ts +50 -0
- package/dist/evaluators/plugin-interface.d.ts.map +1 -0
- package/dist/evaluators/plugin-interface.js +2 -0
- package/dist/evaluators/plugin-interface.js.map +1 -0
- package/dist/evaluators/plugin-loader.d.ts +18 -0
- package/dist/evaluators/plugin-loader.d.ts.map +1 -0
- package/dist/evaluators/plugin-loader.js +107 -0
- package/dist/evaluators/plugin-loader.js.map +1 -0
- package/dist/evaluators/registry.d.ts +78 -0
- package/dist/evaluators/registry.d.ts.map +1 -0
- package/dist/evaluators/registry.js +238 -0
- package/dist/evaluators/registry.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator/context-handoff.d.ts +543 -0
- package/dist/orchestrator/context-handoff.d.ts.map +1 -0
- package/dist/orchestrator/context-handoff.js +133 -0
- package/dist/orchestrator/context-handoff.js.map +1 -0
- package/dist/orchestrator/evaluator-agent.d.ts +15 -0
- package/dist/orchestrator/evaluator-agent.d.ts.map +1 -0
- package/dist/orchestrator/evaluator-agent.js +233 -0
- package/dist/orchestrator/evaluator-agent.js.map +1 -0
- package/dist/orchestrator/generator-agent.d.ts +16 -0
- package/dist/orchestrator/generator-agent.d.ts.map +1 -0
- package/dist/orchestrator/generator-agent.js +147 -0
- package/dist/orchestrator/generator-agent.js.map +1 -0
- package/dist/orchestrator/pipeline.d.ts +24 -0
- package/dist/orchestrator/pipeline.d.ts.map +1 -0
- package/dist/orchestrator/pipeline.js +290 -0
- package/dist/orchestrator/pipeline.js.map +1 -0
- package/dist/orchestrator/planner-agent.d.ts +10 -0
- package/dist/orchestrator/planner-agent.d.ts.map +1 -0
- package/dist/orchestrator/planner-agent.js +187 -0
- package/dist/orchestrator/planner-agent.js.map +1 -0
- package/dist/state/helpers.d.ts +5 -0
- package/dist/state/helpers.d.ts.map +1 -0
- package/dist/state/helpers.js +8 -0
- package/dist/state/helpers.js.map +1 -0
- package/dist/state/history.d.ts +39 -0
- package/dist/state/history.d.ts.map +1 -0
- package/dist/state/history.js +162 -0
- package/dist/state/history.js.map +1 -0
- package/dist/state/index.d.ts +8 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +22 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/plan-state.d.ts +21 -0
- package/dist/state/plan-state.d.ts.map +1 -0
- package/dist/state/plan-state.js +108 -0
- package/dist/state/plan-state.js.map +1 -0
- package/dist/state/sprint-state.d.ts +20 -0
- package/dist/state/sprint-state.d.ts.map +1 -0
- package/dist/state/sprint-state.js +98 -0
- package/dist/state/sprint-state.js.map +1 -0
- package/dist/utils/fs.d.ts +31 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +67 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/git.d.ts +35 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +84 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +45 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +73 -0
- package/dist/utils/logger.js.map +1 -0
- package/hooks/hooks.json +10 -0
- package/package.json +67 -0
- package/scripts/detect-stack.sh +287 -0
- package/scripts/init-project.sh +206 -0
- package/scripts/run-eval.sh +175 -0
- package/skills/bober.anchor/SKILL.md +365 -0
- package/skills/bober.anchor/references/anchor-guide.md +567 -0
- package/skills/bober.brownfield/SKILL.md +422 -0
- package/skills/bober.brownfield/references/codebase-analysis.md +304 -0
- package/skills/bober.eval/SKILL.md +235 -0
- package/skills/bober.eval/references/eval-strategies.md +407 -0
- package/skills/bober.eval/references/feedback-format.md +182 -0
- package/skills/bober.plan/SKILL.md +244 -0
- package/skills/bober.plan/references/clarification-guide.md +124 -0
- package/skills/bober.plan/references/spec-schema.md +253 -0
- package/skills/bober.react/SKILL.md +330 -0
- package/skills/bober.react/references/react-scaffold.md +344 -0
- package/skills/bober.run/SKILL.md +303 -0
- package/skills/bober.solidity/SKILL.md +416 -0
- package/skills/bober.solidity/references/solidity-guide.md +487 -0
- package/skills/bober.sprint/SKILL.md +280 -0
- package/skills/bober.sprint/references/contract-schema.md +251 -0
- package/templates/base/CLAUDE.md +20 -0
- package/templates/base/bober.config.json +35 -0
- package/templates/brownfield/CLAUDE.md +34 -0
- package/templates/brownfield/bober.config.json +37 -0
- package/templates/presets/anchor/CLAUDE.md +163 -0
- package/templates/presets/anchor/bober.config.json +9 -0
- package/templates/presets/api-node/CLAUDE.md +153 -0
- package/templates/presets/api-node/bober.config.json +10 -0
- package/templates/presets/nextjs/CLAUDE.md +82 -0
- package/templates/presets/nextjs/bober.config.json +14 -0
- package/templates/presets/python-api/CLAUDE.md +202 -0
- package/templates/presets/python-api/bober.config.json +9 -0
- package/templates/presets/react-vite/CLAUDE.md +71 -0
- package/templates/presets/react-vite/bober.config.json +53 -0
- package/templates/presets/react-vite/scaffold/package.json +45 -0
- package/templates/presets/react-vite/scaffold/server/index.ts +38 -0
- package/templates/presets/react-vite/scaffold/server/tsconfig.json +24 -0
- package/templates/presets/react-vite/scaffold/src/App.tsx +37 -0
- package/templates/presets/react-vite/scaffold/src/index.html +12 -0
- package/templates/presets/react-vite/scaffold/src/main.tsx +12 -0
- package/templates/presets/react-vite/scaffold/tsconfig.json +27 -0
- package/templates/presets/react-vite/scaffold/vite.config.ts +34 -0
- package/templates/presets/solidity/CLAUDE.md +106 -0
- package/templates/presets/solidity/bober.config.json +9 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Solana/Anchor Project Guide
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
|
|
5
|
+
This is a Solana program built with the Anchor framework.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
programs/ Anchor programs (Rust)
|
|
9
|
+
my-program/
|
|
10
|
+
src/
|
|
11
|
+
lib.rs Program entry point, instruction handlers
|
|
12
|
+
state.rs Account data structures
|
|
13
|
+
error.rs Custom error definitions
|
|
14
|
+
instructions/ Instruction handler modules
|
|
15
|
+
tests/ TypeScript integration tests
|
|
16
|
+
migrations/ Deployment migration scripts
|
|
17
|
+
Anchor.toml Anchor project configuration
|
|
18
|
+
Cargo.toml Rust workspace configuration
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Program Structure
|
|
22
|
+
|
|
23
|
+
### Account Definitions
|
|
24
|
+
|
|
25
|
+
Define account data structures using `#[account]`:
|
|
26
|
+
|
|
27
|
+
```rust
|
|
28
|
+
#[account]
|
|
29
|
+
pub struct GameState {
|
|
30
|
+
pub authority: Pubkey,
|
|
31
|
+
pub score: u64,
|
|
32
|
+
pub bump: u8,
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Always include a `bump` field for PDA accounts. Calculate space with `8 (discriminator) + field sizes`.
|
|
37
|
+
|
|
38
|
+
### Instructions
|
|
39
|
+
|
|
40
|
+
Define instruction contexts using `#[derive(Accounts)]`:
|
|
41
|
+
|
|
42
|
+
```rust
|
|
43
|
+
#[derive(Accounts)]
|
|
44
|
+
pub struct Initialize<'info> {
|
|
45
|
+
#[account(mut)]
|
|
46
|
+
pub authority: Signer<'info>,
|
|
47
|
+
#[account(
|
|
48
|
+
init,
|
|
49
|
+
payer = authority,
|
|
50
|
+
space = 8 + GameState::INIT_SPACE,
|
|
51
|
+
seeds = [b"game", authority.key().as_ref()],
|
|
52
|
+
bump,
|
|
53
|
+
)]
|
|
54
|
+
pub game_state: Account<'info, GameState>,
|
|
55
|
+
pub system_program: Program<'info, System>,
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### PDAs (Program Derived Addresses)
|
|
60
|
+
|
|
61
|
+
- Use `seeds` and `bump` constraints in account validation.
|
|
62
|
+
- Derive PDAs with meaningful seed combinations (e.g., `[b"user", user_pubkey]`).
|
|
63
|
+
- Store the bump in the account to avoid recomputing it.
|
|
64
|
+
- Use `#[account(seeds = [...], bump = account.bump)]` for subsequent accesses.
|
|
65
|
+
|
|
66
|
+
### CPIs (Cross-Program Invocations)
|
|
67
|
+
|
|
68
|
+
Use `CpiContext` for calling other programs:
|
|
69
|
+
|
|
70
|
+
```rust
|
|
71
|
+
let cpi_ctx = CpiContext::new(
|
|
72
|
+
ctx.accounts.token_program.to_account_info(),
|
|
73
|
+
Transfer {
|
|
74
|
+
from: ctx.accounts.source.to_account_info(),
|
|
75
|
+
to: ctx.accounts.destination.to_account_info(),
|
|
76
|
+
authority: ctx.accounts.authority.to_account_info(),
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
token::transfer(cpi_ctx, amount)?;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
For CPIs from PDA-owned accounts, use `CpiContext::new_with_signer` with the PDA seeds.
|
|
83
|
+
|
|
84
|
+
## Commands
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
anchor build # compile the program
|
|
88
|
+
anchor test # build and run all tests
|
|
89
|
+
anchor deploy # deploy to configured cluster
|
|
90
|
+
anchor keys list # show program keypairs
|
|
91
|
+
cargo clippy -- -D warnings # lint Rust code
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## TypeScript Client
|
|
95
|
+
|
|
96
|
+
The TypeScript client is auto-generated by Anchor from the IDL.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import * as anchor from "@coral-xyz/anchor";
|
|
100
|
+
import { Program } from "@coral-xyz/anchor";
|
|
101
|
+
import { MyProgram } from "../target/types/my_program";
|
|
102
|
+
|
|
103
|
+
const program = anchor.workspace.MyProgram as Program<MyProgram>;
|
|
104
|
+
|
|
105
|
+
// Call an instruction
|
|
106
|
+
await program.methods
|
|
107
|
+
.initialize()
|
|
108
|
+
.accounts({
|
|
109
|
+
authority: wallet.publicKey,
|
|
110
|
+
gameState: gameStatePda,
|
|
111
|
+
systemProgram: anchor.web3.SystemProgram.programId,
|
|
112
|
+
})
|
|
113
|
+
.rpc();
|
|
114
|
+
|
|
115
|
+
// Fetch account data
|
|
116
|
+
const state = await program.account.gameState.fetch(gameStatePda);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Testing
|
|
120
|
+
|
|
121
|
+
### With Bankrun (Recommended)
|
|
122
|
+
|
|
123
|
+
Bankrun provides a fast, lightweight test environment:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import { startAnchor } from "solana-bankrun";
|
|
127
|
+
import { BankrunProvider } from "anchor-bankrun";
|
|
128
|
+
|
|
129
|
+
const context = await startAnchor(".", [], []);
|
|
130
|
+
const provider = new BankrunProvider(context);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### With Local Validator
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import * as anchor from "@coral-xyz/anchor";
|
|
137
|
+
|
|
138
|
+
describe("my-program", () => {
|
|
139
|
+
anchor.setProvider(anchor.AnchorProvider.env());
|
|
140
|
+
const program = anchor.workspace.MyProgram;
|
|
141
|
+
|
|
142
|
+
it("initializes", async () => {
|
|
143
|
+
// test code
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Testing Best Practices
|
|
149
|
+
|
|
150
|
+
- Test all instruction handlers with valid inputs.
|
|
151
|
+
- Test constraint violations (wrong signer, wrong PDA, insufficient funds).
|
|
152
|
+
- Test edge cases (zero amounts, max values, duplicate operations).
|
|
153
|
+
- Verify account state after each instruction.
|
|
154
|
+
- Test PDA derivation matches expected addresses.
|
|
155
|
+
|
|
156
|
+
## Coding Conventions
|
|
157
|
+
|
|
158
|
+
- Use `msg!()` for logging (visible in transaction logs).
|
|
159
|
+
- Define custom errors with `#[error_code]` for meaningful error messages.
|
|
160
|
+
- Use `require!()` and `require_keys_eq!()` for input validation.
|
|
161
|
+
- Keep instruction handlers thin. Extract business logic into helper functions.
|
|
162
|
+
- Use `impl` blocks on account structs for data methods.
|
|
163
|
+
- Follow Rust naming conventions: `snake_case` for functions, `PascalCase` for types.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"project": { "name": "my-program", "mode": "greenfield", "preset": "anchor" },
|
|
3
|
+
"evaluator": { "model": "sonnet", "strategies": [
|
|
4
|
+
{ "type": "build", "required": true },
|
|
5
|
+
{ "type": "unit-test", "required": true },
|
|
6
|
+
{ "type": "lint", "required": true }
|
|
7
|
+
], "maxIterations": 3 },
|
|
8
|
+
"commands": { "build": "anchor build", "test": "anchor test", "lint": "cargo clippy -- -D warnings" }
|
|
9
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Node.js API Project Guide
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
|
|
5
|
+
This is a Node.js API project using TypeScript.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/
|
|
9
|
+
index.ts Application entry point
|
|
10
|
+
routes/ Route handlers organized by domain
|
|
11
|
+
middleware/ Express/Fastify middleware (auth, validation, error handling)
|
|
12
|
+
services/ Business logic layer
|
|
13
|
+
models/ Data models / database schemas
|
|
14
|
+
utils/ Shared utility functions
|
|
15
|
+
types/ TypeScript type definitions
|
|
16
|
+
tests/ Test files mirroring src/ structure
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Framework Patterns
|
|
20
|
+
|
|
21
|
+
### Express
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import express from "express";
|
|
25
|
+
const app = express();
|
|
26
|
+
|
|
27
|
+
app.use(express.json());
|
|
28
|
+
app.use("/api/users", userRouter);
|
|
29
|
+
|
|
30
|
+
app.use(errorHandler); // error middleware last
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### NestJS
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
@Controller("users")
|
|
37
|
+
export class UsersController {
|
|
38
|
+
constructor(private readonly usersService: UsersService) {}
|
|
39
|
+
|
|
40
|
+
@Get()
|
|
41
|
+
findAll() {
|
|
42
|
+
return this.usersService.findAll();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@Post()
|
|
46
|
+
create(@Body() dto: CreateUserDto) {
|
|
47
|
+
return this.usersService.create(dto);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Fastify
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import Fastify from "fastify";
|
|
56
|
+
const app = Fastify({ logger: true });
|
|
57
|
+
|
|
58
|
+
app.register(userRoutes, { prefix: "/api/users" });
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Middleware
|
|
62
|
+
|
|
63
|
+
- **Authentication**: Verify JWTs or session tokens. Return 401 for missing/invalid auth.
|
|
64
|
+
- **Validation**: Validate request bodies and query parameters at the route level. Use Zod, Joi, or class-validator.
|
|
65
|
+
- **Error Handling**: Centralize error handling in a global error middleware. Map known errors to HTTP status codes.
|
|
66
|
+
- **Logging**: Use structured logging (pino, winston). Log request IDs for traceability.
|
|
67
|
+
- **Rate Limiting**: Apply rate limiting to public endpoints.
|
|
68
|
+
- **CORS**: Configure CORS for allowed origins.
|
|
69
|
+
|
|
70
|
+
## Validation
|
|
71
|
+
|
|
72
|
+
Use Zod for request validation:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { z } from "zod";
|
|
76
|
+
|
|
77
|
+
const CreateUserSchema = z.object({
|
|
78
|
+
email: z.string().email(),
|
|
79
|
+
name: z.string().min(1).max(100),
|
|
80
|
+
role: z.enum(["admin", "user"]).default("user"),
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
type CreateUserInput = z.infer<typeof CreateUserSchema>;
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Authentication
|
|
87
|
+
|
|
88
|
+
- Use JWT tokens for stateless auth or sessions for stateful auth.
|
|
89
|
+
- Store secrets in environment variables, never in code.
|
|
90
|
+
- Hash passwords with bcrypt (cost factor >= 12).
|
|
91
|
+
- Implement refresh token rotation for long-lived sessions.
|
|
92
|
+
|
|
93
|
+
## Database Access
|
|
94
|
+
|
|
95
|
+
- Use an ORM (Prisma, TypeORM, Drizzle) or query builder (Knex).
|
|
96
|
+
- Run migrations for schema changes. Never modify the database schema manually.
|
|
97
|
+
- Use connection pooling in production.
|
|
98
|
+
- Write repository or service functions for database queries. Do not put raw queries in route handlers.
|
|
99
|
+
|
|
100
|
+
## Error Handling
|
|
101
|
+
|
|
102
|
+
Define application-specific error classes:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
export class AppError extends Error {
|
|
106
|
+
constructor(
|
|
107
|
+
public statusCode: number,
|
|
108
|
+
message: string,
|
|
109
|
+
public code?: string,
|
|
110
|
+
) {
|
|
111
|
+
super(message);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export class NotFoundError extends AppError {
|
|
116
|
+
constructor(resource: string) {
|
|
117
|
+
super(404, `${resource} not found`, "NOT_FOUND");
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Return consistent error response shapes:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"error": {
|
|
127
|
+
"code": "NOT_FOUND",
|
|
128
|
+
"message": "User not found"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Testing
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npm test # run all tests
|
|
137
|
+
npm run test:watch # run tests in watch mode
|
|
138
|
+
npm run test:coverage # run tests with coverage
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
- **Unit tests**: Test services and utilities in isolation. Mock database and external dependencies.
|
|
142
|
+
- **Integration tests**: Test routes with supertest. Use a test database or in-memory store.
|
|
143
|
+
- **Test structure**: Mirror the `src/` directory in `tests/`. Name test files `*.test.ts`.
|
|
144
|
+
|
|
145
|
+
## Coding Conventions
|
|
146
|
+
|
|
147
|
+
- **TypeScript strict mode** is enabled. No `any` unless absolutely necessary.
|
|
148
|
+
- **ESM only** (`"type": "module"` in package.json). Use `import`/`export`, never `require`.
|
|
149
|
+
- **Async/await** for all asynchronous operations. No raw callbacks.
|
|
150
|
+
- **Environment variables**: Load with `dotenv` or framework-native config. Validate at startup.
|
|
151
|
+
- **File naming**: `kebab-case.ts` for all source files.
|
|
152
|
+
- **Error handling**: Always catch async errors. Use `express-async-errors` or equivalent.
|
|
153
|
+
- **No business logic in route handlers**. Route handlers parse input, call services, and format output.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"project": { "name": "my-api", "mode": "greenfield", "preset": "api-node" },
|
|
3
|
+
"evaluator": { "model": "sonnet", "strategies": [
|
|
4
|
+
{ "type": "typecheck", "required": true },
|
|
5
|
+
{ "type": "lint", "required": true },
|
|
6
|
+
{ "type": "unit-test", "required": true },
|
|
7
|
+
{ "type": "api-check", "required": false }
|
|
8
|
+
], "maxIterations": 3 },
|
|
9
|
+
"commands": { "build": "npm run build", "test": "npm test", "lint": "npm run lint", "typecheck": "npx tsc --noEmit", "dev": "npm run dev" }
|
|
10
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Next.js Project Guide
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
|
|
5
|
+
This is a Next.js application using the App Router.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
app/ App Router pages and layouts
|
|
9
|
+
layout.tsx Root layout
|
|
10
|
+
page.tsx Home page
|
|
11
|
+
api/ API routes (Route Handlers)
|
|
12
|
+
components/ Shared React components
|
|
13
|
+
lib/ Utility functions, database clients, helpers
|
|
14
|
+
prisma/ Prisma schema and migrations (if using Prisma)
|
|
15
|
+
public/ Static assets
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## App Router Conventions
|
|
19
|
+
|
|
20
|
+
- **Layouts** (`layout.tsx`): Shared UI that wraps child routes. The root layout is required and must render `<html>` and `<body>`.
|
|
21
|
+
- **Pages** (`page.tsx`): Unique UI for a route. This is what gets rendered at that URL.
|
|
22
|
+
- **Loading** (`loading.tsx`): Loading UI shown while a route segment loads.
|
|
23
|
+
- **Error** (`error.tsx`): Error boundary for a route segment. Must be a Client Component.
|
|
24
|
+
- **Route Handlers** (`route.ts` in `app/api/`): Server-side API endpoints using `GET`, `POST`, etc. exports.
|
|
25
|
+
|
|
26
|
+
## Server vs Client Components
|
|
27
|
+
|
|
28
|
+
- Components are **Server Components** by default. They run on the server, can fetch data directly, and cannot use hooks or browser APIs.
|
|
29
|
+
- Add `"use client"` at the top of a file to make it a **Client Component**. Use Client Components only when you need interactivity (hooks, event handlers, browser APIs).
|
|
30
|
+
- Keep Client Components as leaf nodes in the component tree. Push interactive parts to the smallest possible component.
|
|
31
|
+
|
|
32
|
+
## Server Actions
|
|
33
|
+
|
|
34
|
+
- Use `"use server"` at the top of a file or inside a function to define Server Actions.
|
|
35
|
+
- Server Actions run on the server and can be called from Client Components via form actions or direct invocation.
|
|
36
|
+
- Use Server Actions for data mutations (create, update, delete). Revalidate data with `revalidatePath` or `revalidateTag` after mutations.
|
|
37
|
+
|
|
38
|
+
## Data Fetching
|
|
39
|
+
|
|
40
|
+
- Fetch data in Server Components using `async/await` directly. No need for `useEffect` or client-side fetching for initial data.
|
|
41
|
+
- Use `fetch()` with Next.js caching options: `{ cache: "force-cache" }` (default), `{ cache: "no-store" }`, or `{ next: { revalidate: 60 } }`.
|
|
42
|
+
- For database access, call Prisma or your ORM directly in Server Components.
|
|
43
|
+
|
|
44
|
+
## Middleware
|
|
45
|
+
|
|
46
|
+
- `middleware.ts` at the project root intercepts requests before they reach routes.
|
|
47
|
+
- Use middleware for authentication checks, redirects, request rewriting, and header manipulation.
|
|
48
|
+
|
|
49
|
+
## Testing
|
|
50
|
+
|
|
51
|
+
- **Unit tests**: Use Vitest with `@testing-library/react` for component tests.
|
|
52
|
+
- **Integration tests**: Test API routes by importing the handler and calling it with mock `Request` objects.
|
|
53
|
+
- **E2E tests**: Use Playwright for full end-to-end testing against the running application.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm test # run unit tests
|
|
57
|
+
npm run test:e2e # run Playwright E2E tests
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Database (Prisma)
|
|
61
|
+
|
|
62
|
+
If using Prisma:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx prisma generate # generate client after schema changes
|
|
66
|
+
npx prisma db push # push schema to database (development)
|
|
67
|
+
npx prisma migrate dev # create a migration (development)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- Define models in `prisma/schema.prisma`.
|
|
71
|
+
- Import `PrismaClient` from a singleton in `lib/db.ts`.
|
|
72
|
+
- Never import Prisma in Client Components.
|
|
73
|
+
|
|
74
|
+
## Coding Conventions
|
|
75
|
+
|
|
76
|
+
- **TypeScript strict mode** is enabled. No `any` unless absolutely necessary.
|
|
77
|
+
- **ESM only**. Use `import`/`export`, never `require`.
|
|
78
|
+
- **Functional components** with hooks. No class components.
|
|
79
|
+
- **Server Components by default**. Only add `"use client"` when interactivity is needed.
|
|
80
|
+
- **File naming**: `kebab-case.ts` for utilities, `PascalCase.tsx` for components.
|
|
81
|
+
- **Error handling**: API routes must return appropriate HTTP status codes. Use `NextResponse.json()` for responses.
|
|
82
|
+
- **Environment variables**: Access server-side env vars directly. Prefix with `NEXT_PUBLIC_` for client-side access.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"project": { "name": "my-nextjs-app", "mode": "greenfield", "preset": "nextjs" },
|
|
3
|
+
"planner": { "maxClarifications": 5, "model": "opus" },
|
|
4
|
+
"generator": { "model": "sonnet", "maxTurnsPerSprint": 50, "autoCommit": true, "branchPattern": "bober/{feature-name}" },
|
|
5
|
+
"evaluator": { "model": "sonnet", "strategies": [
|
|
6
|
+
{ "type": "typecheck", "required": true },
|
|
7
|
+
{ "type": "lint", "required": true },
|
|
8
|
+
{ "type": "build", "required": true },
|
|
9
|
+
{ "type": "unit-test", "required": true }
|
|
10
|
+
], "maxIterations": 3 },
|
|
11
|
+
"sprint": { "maxSprints": 10, "requireContracts": true, "sprintSize": "medium" },
|
|
12
|
+
"pipeline": { "maxIterations": 20, "requireApproval": false, "contextReset": "always" },
|
|
13
|
+
"commands": { "install": "npm install", "build": "npm run build", "test": "npm test", "lint": "npm run lint", "dev": "npm run dev", "typecheck": "npx tsc --noEmit" }
|
|
14
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Python API Project Guide
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
|
|
5
|
+
This is a Python API project.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
app/
|
|
9
|
+
main.py Application entry point
|
|
10
|
+
api/
|
|
11
|
+
routes/ Route handlers organized by domain
|
|
12
|
+
deps.py Dependency injection (auth, database sessions)
|
|
13
|
+
models/ SQLAlchemy/Prisma models
|
|
14
|
+
schemas/ Pydantic request/response schemas
|
|
15
|
+
services/ Business logic layer
|
|
16
|
+
core/
|
|
17
|
+
config.py Application settings (pydantic-settings)
|
|
18
|
+
security.py Authentication and authorization
|
|
19
|
+
tests/ Test files mirroring app/ structure
|
|
20
|
+
conftest.py Shared fixtures
|
|
21
|
+
alembic/ Database migrations (if using Alembic)
|
|
22
|
+
pyproject.toml Project configuration and dependencies
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## FastAPI
|
|
26
|
+
|
|
27
|
+
### Application Setup
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from fastapi import FastAPI
|
|
31
|
+
|
|
32
|
+
app = FastAPI(title="My API", version="0.1.0")
|
|
33
|
+
|
|
34
|
+
app.include_router(users_router, prefix="/api/users", tags=["users"])
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Route Handlers
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from fastapi import APIRouter, Depends, HTTPException, status
|
|
41
|
+
|
|
42
|
+
router = APIRouter()
|
|
43
|
+
|
|
44
|
+
@router.get("/", response_model=list[UserResponse])
|
|
45
|
+
async def list_users(db: Session = Depends(get_db)):
|
|
46
|
+
return await user_service.list_all(db)
|
|
47
|
+
|
|
48
|
+
@router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
|
|
49
|
+
async def create_user(data: CreateUserRequest, db: Session = Depends(get_db)):
|
|
50
|
+
return await user_service.create(db, data)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Dependency Injection
|
|
54
|
+
|
|
55
|
+
Use `Depends()` for shared logic (auth, database sessions, pagination):
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
async def get_current_user(token: str = Depends(oauth2_scheme)) -> User:
|
|
59
|
+
payload = verify_token(token)
|
|
60
|
+
user = await get_user_by_id(payload.sub)
|
|
61
|
+
if not user:
|
|
62
|
+
raise HTTPException(status_code=401, detail="Invalid token")
|
|
63
|
+
return user
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Django
|
|
67
|
+
|
|
68
|
+
### URL Configuration
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
urlpatterns = [
|
|
72
|
+
path("api/users/", UserListView.as_view()),
|
|
73
|
+
path("api/users/<int:pk>/", UserDetailView.as_view()),
|
|
74
|
+
]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Views (DRF)
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from rest_framework import viewsets
|
|
81
|
+
from .models import User
|
|
82
|
+
from .serializers import UserSerializer
|
|
83
|
+
|
|
84
|
+
class UserViewSet(viewsets.ModelViewSet):
|
|
85
|
+
queryset = User.objects.all()
|
|
86
|
+
serializer_class = UserSerializer
|
|
87
|
+
permission_classes = [IsAuthenticated]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Pydantic Models
|
|
91
|
+
|
|
92
|
+
Define request and response schemas with Pydantic:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from pydantic import BaseModel, EmailStr
|
|
96
|
+
|
|
97
|
+
class CreateUserRequest(BaseModel):
|
|
98
|
+
email: EmailStr
|
|
99
|
+
name: str
|
|
100
|
+
role: str = "user"
|
|
101
|
+
|
|
102
|
+
class UserResponse(BaseModel):
|
|
103
|
+
id: int
|
|
104
|
+
email: str
|
|
105
|
+
name: str
|
|
106
|
+
role: str
|
|
107
|
+
|
|
108
|
+
model_config = ConfigDict(from_attributes=True)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Database (SQLAlchemy)
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from sqlalchemy import Column, Integer, String
|
|
115
|
+
from app.core.database import Base
|
|
116
|
+
|
|
117
|
+
class User(Base):
|
|
118
|
+
__tablename__ = "users"
|
|
119
|
+
|
|
120
|
+
id = Column(Integer, primary_key=True, index=True)
|
|
121
|
+
email = Column(String, unique=True, index=True, nullable=False)
|
|
122
|
+
name = Column(String, nullable=False)
|
|
123
|
+
hashed_password = Column(String, nullable=False)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Use Alembic for migrations:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
alembic revision --autogenerate -m "add users table"
|
|
130
|
+
alembic upgrade head
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Testing
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
pytest # run all tests
|
|
137
|
+
pytest -v # verbose output
|
|
138
|
+
pytest -x # stop on first failure
|
|
139
|
+
pytest --cov=app # run with coverage
|
|
140
|
+
pytest tests/test_users.py # run specific test file
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Test Structure
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
import pytest
|
|
147
|
+
from httpx import AsyncClient
|
|
148
|
+
from app.main import app
|
|
149
|
+
|
|
150
|
+
@pytest.fixture
|
|
151
|
+
async def client():
|
|
152
|
+
async with AsyncClient(app=app, base_url="http://test") as ac:
|
|
153
|
+
yield ac
|
|
154
|
+
|
|
155
|
+
@pytest.mark.anyio
|
|
156
|
+
async def test_create_user(client: AsyncClient):
|
|
157
|
+
response = await client.post("/api/users/", json={
|
|
158
|
+
"email": "test@example.com",
|
|
159
|
+
"name": "Test User",
|
|
160
|
+
})
|
|
161
|
+
assert response.status_code == 201
|
|
162
|
+
data = response.json()
|
|
163
|
+
assert data["email"] == "test@example.com"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Fixtures
|
|
167
|
+
|
|
168
|
+
Use `conftest.py` for shared fixtures (database sessions, test clients, factory functions).
|
|
169
|
+
|
|
170
|
+
## Type Checking
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
mypy . # type check entire project
|
|
174
|
+
mypy app/services/ # type check specific directory
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Configure in `pyproject.toml`:
|
|
178
|
+
|
|
179
|
+
```toml
|
|
180
|
+
[tool.mypy]
|
|
181
|
+
strict = true
|
|
182
|
+
plugins = ["pydantic.mypy"]
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Linting
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
ruff check . # lint all files
|
|
189
|
+
ruff check --fix . # auto-fix issues
|
|
190
|
+
ruff format . # format code
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Coding Conventions
|
|
194
|
+
|
|
195
|
+
- **Type hints** on all function signatures. Use `strict` mode in mypy.
|
|
196
|
+
- **Async/await** for all I/O operations (database, HTTP, file system).
|
|
197
|
+
- **Pydantic** for all request/response validation. Never trust raw input.
|
|
198
|
+
- **Dependency injection** for database sessions, auth, and shared services.
|
|
199
|
+
- **Environment variables**: Use `pydantic-settings` for configuration. Validate at startup.
|
|
200
|
+
- **File naming**: `snake_case.py` for all source files.
|
|
201
|
+
- **Error handling**: Raise `HTTPException` with appropriate status codes. Use custom exception handlers for domain errors.
|
|
202
|
+
- **No business logic in route handlers**. Route handlers parse input, call services, and return responses.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"project": { "name": "my-api", "mode": "greenfield", "preset": "python-api" },
|
|
3
|
+
"evaluator": { "model": "sonnet", "strategies": [
|
|
4
|
+
{ "type": "lint", "required": true },
|
|
5
|
+
{ "type": "unit-test", "required": true },
|
|
6
|
+
{ "type": "api-check", "required": false }
|
|
7
|
+
], "maxIterations": 3 },
|
|
8
|
+
"commands": { "test": "pytest", "lint": "ruff check .", "typecheck": "mypy ." }
|
|
9
|
+
}
|