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,71 @@
|
|
|
1
|
+
# Project Guide
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
|
|
5
|
+
This is a React + Express full-stack TypeScript application.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/ React frontend (Vite)
|
|
9
|
+
App.tsx Root component
|
|
10
|
+
main.tsx Entry point
|
|
11
|
+
index.html HTML template
|
|
12
|
+
server/ Express backend
|
|
13
|
+
index.ts Server entry point with API routes
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Frontend:** React 19, TypeScript, Vite 6, bundled with `@vitejs/plugin-react`.
|
|
17
|
+
**Backend:** Express 5, TypeScript, running on Node with `tsx` in development.
|
|
18
|
+
|
|
19
|
+
The Vite dev server proxies `/api/*` requests to the Express server at `localhost:3001`.
|
|
20
|
+
|
|
21
|
+
## Running the Project
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install # install all dependencies
|
|
25
|
+
npm run dev # start both frontend (5173) and backend (3001)
|
|
26
|
+
npm run dev:client # start only the Vite dev server
|
|
27
|
+
npm run dev:server # start only the Express server
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Building
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm run build # builds both client and server
|
|
34
|
+
npm run build:client # vite build -> dist/client/
|
|
35
|
+
npm run build:server # tsc -> dist/server/
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Testing
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm test # run unit tests with Vitest
|
|
42
|
+
npm run test:watch # run Vitest in watch mode
|
|
43
|
+
npm run test:e2e # run Playwright end-to-end tests
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Unit tests live alongside source files as `*.test.ts` or `*.test.tsx`. Use `@testing-library/react` for component tests. Use `vitest` globals (`describe`, `it`, `expect`).
|
|
47
|
+
|
|
48
|
+
## Linting and Type Checking
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm run lint # ESLint across all .ts/.tsx files
|
|
52
|
+
npm run typecheck # tsc --noEmit for both client and server
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Coding Conventions
|
|
56
|
+
|
|
57
|
+
- **TypeScript strict mode** is enabled everywhere. No `any` unless absolutely necessary.
|
|
58
|
+
- **ESM only** (`"type": "module"` in package.json). Use `import`/`export`, never `require`.
|
|
59
|
+
- **Functional React components** with hooks. No class components.
|
|
60
|
+
- **Path aliases:** Use `@/` to import from `src/` in frontend code.
|
|
61
|
+
- **API routes** are prefixed with `/api/`. All API responses are JSON.
|
|
62
|
+
- **Error handling:** API endpoints must return appropriate HTTP status codes and structured error objects (`{ error: string, details?: unknown }`).
|
|
63
|
+
- **No default exports** except for React page/route components and the Express app.
|
|
64
|
+
- **File naming:** `kebab-case.ts` for utilities, `PascalCase.tsx` for React components.
|
|
65
|
+
|
|
66
|
+
## Key Decisions
|
|
67
|
+
|
|
68
|
+
- Vite is used instead of Next.js for simplicity and separation of concerns.
|
|
69
|
+
- The backend is a standalone Express server, not a serverless function layer.
|
|
70
|
+
- Vitest is used for unit tests (Vite-native, fast, compatible API).
|
|
71
|
+
- Playwright handles E2E testing against the running application.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"project": {
|
|
3
|
+
"name": "",
|
|
4
|
+
"mode": "greenfield",
|
|
5
|
+
"preset": "react-vite",
|
|
6
|
+
"description": "React + Vite frontend with Express backend"
|
|
7
|
+
},
|
|
8
|
+
"planner": {
|
|
9
|
+
"maxClarifications": 5,
|
|
10
|
+
"model": "opus",
|
|
11
|
+
"contextFiles": [
|
|
12
|
+
"package.json",
|
|
13
|
+
"tsconfig.json",
|
|
14
|
+
"vite.config.ts",
|
|
15
|
+
"server/index.ts"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"generator": {
|
|
19
|
+
"model": "sonnet",
|
|
20
|
+
"maxTurnsPerSprint": 50,
|
|
21
|
+
"autoCommit": true,
|
|
22
|
+
"branchPattern": "bober/{feature-name}"
|
|
23
|
+
},
|
|
24
|
+
"evaluator": {
|
|
25
|
+
"model": "sonnet",
|
|
26
|
+
"strategies": [
|
|
27
|
+
{ "type": "typecheck", "required": true },
|
|
28
|
+
{ "type": "lint", "required": true },
|
|
29
|
+
{ "type": "build", "required": true },
|
|
30
|
+
{ "type": "unit-test", "required": true },
|
|
31
|
+
{ "type": "playwright", "required": false }
|
|
32
|
+
],
|
|
33
|
+
"maxIterations": 3
|
|
34
|
+
},
|
|
35
|
+
"sprint": {
|
|
36
|
+
"maxSprints": 10,
|
|
37
|
+
"requireContracts": true,
|
|
38
|
+
"sprintSize": "medium"
|
|
39
|
+
},
|
|
40
|
+
"pipeline": {
|
|
41
|
+
"maxIterations": 20,
|
|
42
|
+
"requireApproval": false,
|
|
43
|
+
"contextReset": "always"
|
|
44
|
+
},
|
|
45
|
+
"commands": {
|
|
46
|
+
"install": "npm install",
|
|
47
|
+
"build": "npm run build",
|
|
48
|
+
"test": "npm test",
|
|
49
|
+
"lint": "npm run lint",
|
|
50
|
+
"dev": "npm run dev",
|
|
51
|
+
"typecheck": "npx tsc --noEmit"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "concurrently \"npm run dev:client\" \"npm run dev:server\"",
|
|
8
|
+
"dev:client": "vite",
|
|
9
|
+
"dev:server": "tsx watch server/index.ts",
|
|
10
|
+
"build": "npm run build:client && npm run build:server",
|
|
11
|
+
"build:client": "vite build",
|
|
12
|
+
"build:server": "tsc -p server/tsconfig.json",
|
|
13
|
+
"preview": "vite preview",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"test:watch": "vitest",
|
|
16
|
+
"test:e2e": "playwright test",
|
|
17
|
+
"lint": "eslint . --ext .ts,.tsx",
|
|
18
|
+
"typecheck": "tsc --noEmit && tsc -p server/tsconfig.json --noEmit"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"express": "^5.0.1",
|
|
22
|
+
"react": "^19.0.0",
|
|
23
|
+
"react-dom": "^19.0.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@eslint/js": "^9.19.0",
|
|
27
|
+
"@playwright/test": "^1.50.0",
|
|
28
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
29
|
+
"@testing-library/react": "^16.2.0",
|
|
30
|
+
"@types/express": "^5.0.0",
|
|
31
|
+
"@types/node": "^22.13.0",
|
|
32
|
+
"@types/react": "^19.0.8",
|
|
33
|
+
"@types/react-dom": "^19.0.3",
|
|
34
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
35
|
+
"concurrently": "^9.1.2",
|
|
36
|
+
"eslint": "^9.19.0",
|
|
37
|
+
"globals": "^15.14.0",
|
|
38
|
+
"jsdom": "^26.0.0",
|
|
39
|
+
"tsx": "^4.19.2",
|
|
40
|
+
"typescript": "^5.7.3",
|
|
41
|
+
"typescript-eslint": "^8.22.0",
|
|
42
|
+
"vite": "^6.0.11",
|
|
43
|
+
"vitest": "^3.0.5"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const app = express();
|
|
7
|
+
const PORT = Number(process.env.PORT) || 3001;
|
|
8
|
+
|
|
9
|
+
// -- Middleware ----------------------------------------------------------
|
|
10
|
+
app.use(express.json());
|
|
11
|
+
|
|
12
|
+
// -- API Routes ----------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
app.get("/api/health", (_req, res) => {
|
|
15
|
+
res.json({
|
|
16
|
+
status: "ok",
|
|
17
|
+
timestamp: new Date().toISOString(),
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// -- Static Serving (production) -----------------------------------------
|
|
22
|
+
// In production, serve the built Vite client from dist/client.
|
|
23
|
+
if (process.env.NODE_ENV === "production") {
|
|
24
|
+
const clientDist = path.resolve(__dirname, "../client");
|
|
25
|
+
app.use(express.static(clientDist));
|
|
26
|
+
|
|
27
|
+
// SPA fallback: serve index.html for any non-API route.
|
|
28
|
+
app.get("*", (_req, res) => {
|
|
29
|
+
res.sendFile(path.join(clientDist, "index.html"));
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// -- Start ---------------------------------------------------------------
|
|
34
|
+
app.listen(PORT, () => {
|
|
35
|
+
console.log(`Server running at http://localhost:${PORT}`);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export default app;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "../dist/server",
|
|
8
|
+
"rootDir": ".",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"declaration": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"isolatedModules": true,
|
|
17
|
+
"noUnusedLocals": true,
|
|
18
|
+
"noUnusedParameters": true,
|
|
19
|
+
"noImplicitReturns": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true
|
|
21
|
+
},
|
|
22
|
+
"include": ["./**/*.ts"],
|
|
23
|
+
"exclude": ["node_modules"]
|
|
24
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useState, useEffect } from "react";
|
|
2
|
+
|
|
3
|
+
interface HealthStatus {
|
|
4
|
+
status: string;
|
|
5
|
+
timestamp: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default function App() {
|
|
9
|
+
const [health, setHealth] = useState<HealthStatus | null>(null);
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
fetch("/api/health")
|
|
13
|
+
.then((res) => res.json())
|
|
14
|
+
.then((data: HealthStatus) => setHealth(data))
|
|
15
|
+
.catch(() => setHealth(null));
|
|
16
|
+
}, []);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<main style={{ maxWidth: 640, margin: "0 auto", padding: "2rem" }}>
|
|
20
|
+
<h1>Welcome to Your App</h1>
|
|
21
|
+
<p>
|
|
22
|
+
Edit <code>src/App.tsx</code> to get started.
|
|
23
|
+
</p>
|
|
24
|
+
<section>
|
|
25
|
+
<h2>API Status</h2>
|
|
26
|
+
{health ? (
|
|
27
|
+
<p>
|
|
28
|
+
Server is <strong>{health.status}</strong> (checked at{" "}
|
|
29
|
+
{new Date(health.timestamp).toLocaleTimeString()})
|
|
30
|
+
</p>
|
|
31
|
+
) : (
|
|
32
|
+
<p>Connecting to server...</p>
|
|
33
|
+
)}
|
|
34
|
+
</section>
|
|
35
|
+
</main>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>App</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { StrictMode } from "react";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import App from "./App.tsx";
|
|
4
|
+
|
|
5
|
+
const rootEl = document.getElementById("root");
|
|
6
|
+
if (!rootEl) throw new Error("Missing #root element in index.html");
|
|
7
|
+
|
|
8
|
+
createRoot(rootEl).render(
|
|
9
|
+
<StrictMode>
|
|
10
|
+
<App />
|
|
11
|
+
</StrictMode>,
|
|
12
|
+
);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "Bundler",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"noImplicitReturns": true,
|
|
18
|
+
"noFallthroughCasesInSwitch": true,
|
|
19
|
+
"allowImportingTsExtensions": true,
|
|
20
|
+
"baseUrl": ".",
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["src/*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"include": ["src/**/*", "vite-env.d.ts"],
|
|
26
|
+
"exclude": ["node_modules", "dist", "server"]
|
|
27
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import react from "@vitejs/plugin-react";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [react()],
|
|
7
|
+
root: "src",
|
|
8
|
+
publicDir: path.resolve(__dirname, "public"),
|
|
9
|
+
resolve: {
|
|
10
|
+
alias: {
|
|
11
|
+
"@": path.resolve(__dirname, "src"),
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
server: {
|
|
15
|
+
port: 5173,
|
|
16
|
+
proxy: {
|
|
17
|
+
"/api": {
|
|
18
|
+
target: "http://localhost:3001",
|
|
19
|
+
changeOrigin: true,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
build: {
|
|
24
|
+
outDir: path.resolve(__dirname, "dist/client"),
|
|
25
|
+
emptyOutDir: true,
|
|
26
|
+
sourcemap: true,
|
|
27
|
+
},
|
|
28
|
+
test: {
|
|
29
|
+
globals: true,
|
|
30
|
+
environment: "jsdom",
|
|
31
|
+
setupFiles: [],
|
|
32
|
+
css: true,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Solidity Project Guide
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
|
|
5
|
+
This is an EVM smart contract project using Hardhat (or Foundry).
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
contracts/ Solidity source files
|
|
9
|
+
interfaces/ Interface definitions
|
|
10
|
+
libraries/ Shared library contracts
|
|
11
|
+
test/ Test files (Chai/Mocha for Hardhat, Forge tests for Foundry)
|
|
12
|
+
scripts/ Deployment and utility scripts
|
|
13
|
+
hardhat.config.ts Hardhat configuration
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Hardhat Setup
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx hardhat compile # compile all contracts
|
|
20
|
+
npx hardhat test # run the test suite
|
|
21
|
+
npx hardhat test --grep "transfer" # run tests matching a pattern
|
|
22
|
+
npx hardhat node # start a local Hardhat node
|
|
23
|
+
npx hardhat run scripts/deploy.ts --network localhost # deploy locally
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
If using Foundry alongside Hardhat:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
forge build # compile with Foundry
|
|
30
|
+
forge test # run Foundry tests
|
|
31
|
+
forge test -vvv # run with verbose output (traces)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Contract Structure
|
|
35
|
+
|
|
36
|
+
- Each contract goes in its own file under `contracts/`.
|
|
37
|
+
- Use a consistent naming convention: `ContractName.sol` matches the contract name inside.
|
|
38
|
+
- Inherit from OpenZeppelin contracts where possible instead of reimplementing standard functionality.
|
|
39
|
+
- Define interfaces in `contracts/interfaces/` and implement them in concrete contracts.
|
|
40
|
+
|
|
41
|
+
## OpenZeppelin Usage
|
|
42
|
+
|
|
43
|
+
- Import OpenZeppelin contracts from `@openzeppelin/contracts`.
|
|
44
|
+
- Common imports: `ERC20`, `ERC721`, `ERC1155`, `Ownable`, `AccessControl`, `ReentrancyGuard`, `Pausable`.
|
|
45
|
+
- For upgradeable contracts, use `@openzeppelin/contracts-upgradeable` and initialize in an `initialize()` function instead of a constructor.
|
|
46
|
+
|
|
47
|
+
## Testing
|
|
48
|
+
|
|
49
|
+
- Write tests in TypeScript using Chai assertions and Mocha structure (`describe`, `it`).
|
|
50
|
+
- Use `ethers.getSigners()` to get test accounts.
|
|
51
|
+
- Use `loadFixture` from `@nomicfoundation/hardhat-toolbox` to snapshot and revert state between tests.
|
|
52
|
+
- Test all success paths, revert conditions, event emissions, and edge cases.
|
|
53
|
+
- Use `expect(...).to.be.revertedWith("message")` or `revertedWithCustomError` for revert testing.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
|
|
57
|
+
import { expect } from "chai";
|
|
58
|
+
import hre from "hardhat";
|
|
59
|
+
|
|
60
|
+
describe("MyContract", function () {
|
|
61
|
+
async function deployFixture() {
|
|
62
|
+
const [owner, other] = await hre.ethers.getSigners();
|
|
63
|
+
const MyContract = await hre.ethers.getContractFactory("MyContract");
|
|
64
|
+
const contract = await MyContract.deploy();
|
|
65
|
+
return { contract, owner, other };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
it("should do something", async function () {
|
|
69
|
+
const { contract, owner } = await loadFixture(deployFixture);
|
|
70
|
+
expect(await contract.owner()).to.equal(owner.address);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Deployment Scripts
|
|
76
|
+
|
|
77
|
+
- Place deployment scripts in `scripts/`.
|
|
78
|
+
- Use `hardhat-deploy` plugin or write custom scripts with `ethers`.
|
|
79
|
+
- Always verify contracts on block explorers after deployment.
|
|
80
|
+
|
|
81
|
+
## Gas Optimization
|
|
82
|
+
|
|
83
|
+
- Use `uint256` instead of smaller uint types unless packing structs.
|
|
84
|
+
- Prefer `calldata` over `memory` for external function parameters that are read-only.
|
|
85
|
+
- Use `immutable` for variables set once in the constructor.
|
|
86
|
+
- Use `constant` for compile-time constants.
|
|
87
|
+
- Minimize storage writes (SSTORE is the most expensive opcode).
|
|
88
|
+
- Use events for data that does not need on-chain reads.
|
|
89
|
+
- Batch operations where possible to amortize base transaction costs.
|
|
90
|
+
|
|
91
|
+
## Security Patterns
|
|
92
|
+
|
|
93
|
+
- **Reentrancy**: Use `ReentrancyGuard` or follow checks-effects-interactions pattern.
|
|
94
|
+
- **Overflow/Underflow**: Solidity 0.8+ has built-in overflow checks. Be careful with `unchecked` blocks.
|
|
95
|
+
- **Access Control**: Use `Ownable` for simple ownership or `AccessControl` for role-based permissions.
|
|
96
|
+
- **Input Validation**: Validate all external inputs with `require` statements at the top of functions.
|
|
97
|
+
- **Frontrunning**: Consider commit-reveal schemes or use flashbots for sensitive transactions.
|
|
98
|
+
- **Upgradability**: If using proxies, follow the UUPS or Transparent Proxy pattern. Never leave an implementation uninitialized.
|
|
99
|
+
|
|
100
|
+
## Linting
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx solhint 'contracts/**/*.sol' # lint Solidity files
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Configure rules in `.solhint.json`. Recommended rules: `compiler-version`, `no-unused-vars`, `reason-string`, `func-visibility`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"project": { "name": "my-contracts", "mode": "greenfield", "preset": "solidity" },
|
|
3
|
+
"evaluator": { "model": "sonnet", "strategies": [
|
|
4
|
+
{ "type": "build", "required": true },
|
|
5
|
+
{ "type": "lint", "required": true },
|
|
6
|
+
{ "type": "unit-test", "required": true }
|
|
7
|
+
], "maxIterations": 3 },
|
|
8
|
+
"commands": { "build": "npx hardhat compile", "test": "npx hardhat test", "lint": "npx solhint 'contracts/**/*.sol'" }
|
|
9
|
+
}
|