@botlearn/code-gen 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 BotLearn
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # @botlearn/code-gen
2
+
3
+ > Complete code generation with proper architecture, error handling, type safety, and test accompaniment for OpenClaw Agent
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # via npm
9
+ npm install @botlearn/code-gen
10
+
11
+ # via clawhub
12
+ clawhub install @botlearn/code-gen
13
+ ```
14
+
15
+ ## Category
16
+
17
+ programming-assistance
18
+
19
+ ## Dependencies
20
+
21
+ None
22
+
23
+ ## Files
24
+
25
+ | File | Description |
26
+ |------|-------------|
27
+ | `manifest.json` | Skill metadata and configuration |
28
+ | `skill.md` | Role definition and activation rules |
29
+ | `knowledge/` | Domain knowledge documents |
30
+ | `strategies/` | Behavioral strategy definitions |
31
+ | `tests/` | Smoke and benchmark tests |
32
+
33
+ ## License
34
+
35
+ MIT
@@ -0,0 +1,212 @@
1
+ ---
2
+ domain: code-gen
3
+ topic: anti-patterns
4
+ priority: medium
5
+ ttl: 30d
6
+ ---
7
+
8
+ # Code Generation — Anti-Patterns
9
+
10
+ ## Type Safety Anti-Patterns
11
+
12
+ ### 1. `any` Type Abuse
13
+ - **Problem**: Using `any` (TypeScript), `object` (C#), or `interface{}` (Go) to bypass the type system, silencing compiler checks and hiding bugs
14
+ - **Impact**: Runtime crashes that should have been caught at compile time; no IDE autocompletion; impossible to refactor safely
15
+ - **Fix**: Use `unknown` with type guards, generic constraints, or explicit union types
16
+ ```typescript
17
+ // BAD
18
+ function processData(data: any): any {
19
+ return data.items.map((i: any) => i.name);
20
+ }
21
+
22
+ // GOOD
23
+ function processData<T extends { items: Array<{ name: string }> }>(data: T): string[] {
24
+ return data.items.map(i => i.name);
25
+ }
26
+ ```
27
+
28
+ ### 2. Stringly-Typed Code
29
+ - **Problem**: Using plain strings for states, roles, event names, and identifiers instead of enums or literal types
30
+ - **Impact**: Typos become silent bugs; no autocompletion; refactoring misses string constants
31
+ - **Fix**: Use string literal unions, enums, or const objects
32
+ ```typescript
33
+ // BAD
34
+ function setStatus(status: string) { ... }
35
+ setStatus("actve"); // Typo — no compiler error
36
+
37
+ // GOOD
38
+ type Status = "active" | "inactive" | "suspended";
39
+ function setStatus(status: Status) { ... }
40
+ setStatus("actve"); // Compiler error
41
+ ```
42
+
43
+ ### 3. Type Assertion Over-Use
44
+ - **Problem**: Using `as Type` or `!` (non-null assertion) to force types instead of proper narrowing
45
+ - **Impact**: Bypasses type safety; runtime will crash when the assertion is wrong
46
+ - **Fix**: Use type guards, null checks, or schema validation
47
+ ```typescript
48
+ // BAD
49
+ const user = response.data as User; // What if data is null?
50
+
51
+ // GOOD
52
+ const parsed = userSchema.safeParse(response.data);
53
+ if (!parsed.success) throw new ValidationError(parsed.error);
54
+ const user = parsed.data;
55
+ ```
56
+
57
+ ## Error Handling Anti-Patterns
58
+
59
+ ### 4. Silent Catch (Swallowed Errors)
60
+ - **Problem**: Catching exceptions and doing nothing — losing error context and hiding failures
61
+ - **Impact**: Bugs become invisible; system enters corrupt state silently; debugging becomes extremely difficult
62
+ - **Fix**: Always log, re-throw, or return an error result. At minimum log the error.
63
+ ```typescript
64
+ // BAD
65
+ try {
66
+ await saveOrder(order);
67
+ } catch (e) {
68
+ // silently swallowed
69
+ }
70
+
71
+ // GOOD
72
+ try {
73
+ await saveOrder(order);
74
+ } catch (error) {
75
+ logger.error("Failed to save order", { orderId: order.id, error });
76
+ throw new OrderPersistenceError(order.id, error);
77
+ }
78
+ ```
79
+
80
+ ### 5. Catching Generic Exceptions
81
+ - **Problem**: Using bare `catch` (Python), `catch (Exception e)` (Java), or `catch (e)` without type narrowing
82
+ - **Impact**: Catches programming errors (null references, type errors) along with expected failures; masks bugs
83
+ - **Fix**: Catch specific error types; let unexpected errors propagate to the global error handler
84
+ ```python
85
+ # BAD
86
+ try:
87
+ result = process_payment(order)
88
+ except Exception:
89
+ return {"error": "something went wrong"}
90
+
91
+ # GOOD
92
+ try:
93
+ result = process_payment(order)
94
+ except PaymentDeclinedError as e:
95
+ return {"error": f"Payment declined: {e.reason}", "code": "PAYMENT_DECLINED"}
96
+ except PaymentGatewayTimeout as e:
97
+ logger.warning("Payment gateway timeout", extra={"order_id": order.id})
98
+ raise RetryableError("Payment processing timed out") from e
99
+ ```
100
+
101
+ ### 6. Error Messages Without Context
102
+ - **Problem**: Throwing errors with generic messages like "An error occurred" or "Invalid input"
103
+ - **Impact**: Debugging requires reproducing the issue; no information about what was expected vs. received
104
+ - **Fix**: Include the field name, the received value (sanitized), and the expected format
105
+ ```typescript
106
+ // BAD
107
+ throw new Error("Invalid input");
108
+
109
+ // GOOD
110
+ throw new ValidationError(
111
+ `Field 'email' is invalid: received '${sanitize(input.email)}', expected a valid email address`
112
+ );
113
+ ```
114
+
115
+ ## Validation Anti-Patterns
116
+
117
+ ### 7. No Input Validation
118
+ - **Problem**: Assuming inputs are well-formed; passing user input directly to database queries, file operations, or shell commands
119
+ - **Impact**: SQL injection, path traversal, command injection, data corruption, and crashes on unexpected types
120
+ - **Fix**: Validate and sanitize all external input at the boundary; use parameterized queries
121
+ ```typescript
122
+ // BAD
123
+ app.get("/users/:id", async (req, res) => {
124
+ const user = await db.query(`SELECT * FROM users WHERE id = '${req.params.id}'`);
125
+ res.json(user);
126
+ });
127
+
128
+ // GOOD
129
+ app.get("/users/:id", async (req, res) => {
130
+ const id = z.string().uuid().parse(req.params.id);
131
+ const user = await db.query("SELECT * FROM users WHERE id = $1", [id]);
132
+ if (!user) throw new NotFoundError("User", id);
133
+ res.json(user);
134
+ });
135
+ ```
136
+
137
+ ### 8. Validation Logic Scattered Across Codebase
138
+ - **Problem**: Validating the same field in multiple places with inconsistent rules
139
+ - **Impact**: Contradictory validation; bypass by calling the inner function directly; maintenance nightmare
140
+ - **Fix**: Define validation schemas once; apply at the API boundary; trust validated data internally
141
+
142
+ ## Architecture Anti-Patterns
143
+
144
+ ### 9. God Function / God Class
145
+ - **Problem**: A single function or class that handles multiple unrelated responsibilities (parse + validate + transform + save + notify)
146
+ - **Impact**: Impossible to test in isolation; changes ripple unpredictably; functions exceed 100 lines
147
+ - **Fix**: Extract each responsibility into a separate function or class; compose them in a pipeline
148
+ ```typescript
149
+ // BAD: one function does everything
150
+ async function handleOrder(rawData: unknown) {
151
+ // 200 lines of parsing, validating, saving, emailing, logging...
152
+ }
153
+
154
+ // GOOD: composed pipeline
155
+ async function handleOrder(rawData: unknown): Promise<OrderResult> {
156
+ const validated = validateOrderInput(rawData);
157
+ const order = buildOrder(validated);
158
+ const saved = await orderRepo.save(order);
159
+ await notificationService.sendConfirmation(saved);
160
+ return toOrderResult(saved);
161
+ }
162
+ ```
163
+
164
+ ### 10. Hard-Coded Configuration
165
+ - **Problem**: Embedding URLs, connection strings, API keys, timeouts, and feature flags directly in source code
166
+ - **Impact**: Cannot change behavior without code changes; secrets leak into version control; different environments require code modifications
167
+ - **Fix**: Use environment variables, configuration files, or a config module with validation
168
+ ```typescript
169
+ // BAD
170
+ const API_URL = "https://api.production.com/v2";
171
+ const TIMEOUT = 5000;
172
+
173
+ // GOOD
174
+ const config = loadConfig({
175
+ apiUrl: envVar("API_URL").required().url(),
176
+ timeout: envVar("REQUEST_TIMEOUT_MS").default(5000).int().min(100).max(60000),
177
+ });
178
+ ```
179
+
180
+ ### 11. Premature Abstraction
181
+ - **Problem**: Creating generic frameworks, complex inheritance hierarchies, or elaborate plugin systems before having concrete use cases
182
+ - **Impact**: Over-engineered code that is harder to understand and modify than the problem warrants; abstractions that don't match real usage patterns
183
+ - **Fix**: Follow the "Rule of Three" — wait until you have three concrete examples before extracting an abstraction. Start concrete, refactor to abstract when patterns emerge.
184
+
185
+ ### 12. Missing Dependency Injection
186
+ - **Problem**: Functions that directly instantiate their dependencies (e.g., `new Database()`, `axios.get()`) instead of accepting them as parameters
187
+ - **Impact**: Impossible to unit test without mocking module internals; tight coupling; cannot swap implementations
188
+ - **Fix**: Accept dependencies as function/constructor parameters; provide defaults for production
189
+ ```typescript
190
+ // BAD: hard-wired dependency
191
+ async function getUser(id: string) {
192
+ const db = new Database(); // untestable
193
+ return db.query("SELECT * FROM users WHERE id = $1", [id]);
194
+ }
195
+
196
+ // GOOD: injectable dependency
197
+ async function getUser(id: string, db: Database = defaultDb): Promise<User | null> {
198
+ return db.query("SELECT * FROM users WHERE id = $1", [id]);
199
+ }
200
+ ```
201
+
202
+ ## Output Anti-Patterns
203
+
204
+ ### 13. Code Without Usage Examples
205
+ - **Problem**: Generating a function or class without showing how to call it
206
+ - **Impact**: User must read the entire implementation to understand the API; incorrect usage leads to bugs
207
+ - **Fix**: Always include at least one usage example with realistic arguments and expected output
208
+
209
+ ### 14. Incomplete Implementations
210
+ - **Problem**: Generating skeleton code with `// TODO` placeholders or `pass` statements in critical paths
211
+ - **Impact**: User deploys incomplete code; runtime failures in production
212
+ - **Fix**: Generate complete implementations; if a feature is beyond scope, throw a `NotImplementedError` with a descriptive message rather than silently passing
@@ -0,0 +1,228 @@
1
+ ---
2
+ domain: code-gen
3
+ topic: type-safety-validation-and-testing
4
+ priority: high
5
+ ttl: 30d
6
+ ---
7
+
8
+ # Code Generation — Best Practices
9
+
10
+ ## Type Safety
11
+
12
+ ### 1. Define Types at the Boundary
13
+ - Define input/output types for every public function, API endpoint, and module boundary
14
+ - Use schema validation libraries (Zod, Pydantic, JSON Schema) to enforce types at runtime boundaries
15
+ - Keep internal logic strongly typed; only marshal/unmarshal at edges
16
+
17
+ ```typescript
18
+ // Define the contract
19
+ interface CreateOrderRequest {
20
+ userId: string;
21
+ items: Array<{ productId: string; quantity: number }>;
22
+ shippingAddress: Address;
23
+ }
24
+
25
+ interface CreateOrderResponse {
26
+ orderId: string;
27
+ status: "pending" | "confirmed";
28
+ estimatedDelivery: string;
29
+ }
30
+
31
+ // Validate at the boundary
32
+ const createOrderSchema = z.object({
33
+ userId: z.string().uuid(),
34
+ items: z.array(z.object({
35
+ productId: z.string().uuid(),
36
+ quantity: z.number().int().positive().max(100),
37
+ })).min(1).max(50),
38
+ shippingAddress: addressSchema,
39
+ });
40
+ ```
41
+
42
+ ### 2. Use Discriminated Unions for State
43
+ - Model mutually exclusive states as discriminated unions instead of optional fields
44
+ - Eliminates impossible states at the type level
45
+
46
+ ```typescript
47
+ // BAD: allows impossible states (loading=true AND error set)
48
+ interface DataState {
49
+ loading: boolean;
50
+ data?: User[];
51
+ error?: string;
52
+ }
53
+
54
+ // GOOD: each state is explicit and exhaustive
55
+ type DataState =
56
+ | { status: "idle" }
57
+ | { status: "loading" }
58
+ | { status: "success"; data: User[] }
59
+ | { status: "error"; error: string; retryCount: number };
60
+ ```
61
+
62
+ ### 3. Prefer Narrow Types Over Broad Ones
63
+ - Use string literal unions instead of `string` for known value sets
64
+ - Use branded/opaque types for domain identifiers to prevent mixing
65
+ - Use `readonly` arrays and objects where mutation is not needed
66
+
67
+ ```typescript
68
+ type Currency = "USD" | "EUR" | "GBP" | "JPY";
69
+ type OrderStatus = "draft" | "pending" | "confirmed" | "shipped" | "delivered" | "cancelled";
70
+
71
+ // Branded types prevent accidental swaps
72
+ type UserId = string & { readonly __brand: unique symbol };
73
+ type OrderId = string & { readonly __brand: unique symbol };
74
+
75
+ function getOrder(orderId: OrderId): Promise<Order>; // Cannot pass UserId here
76
+ ```
77
+
78
+ ## Input Validation
79
+
80
+ ### 4. Validate All External Input
81
+ - Every public API, CLI argument, environment variable, and file read must be validated
82
+ - Fail fast with descriptive error messages that name the invalid field and expected format
83
+ - Never trust client-side validation alone; always re-validate on the server
84
+
85
+ ```typescript
86
+ function validateEnvConfig(): AppConfig {
87
+ const errors: string[] = [];
88
+
89
+ const port = Number(process.env.PORT);
90
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
91
+ errors.push("PORT must be an integer between 1 and 65535");
92
+ }
93
+
94
+ const dbUrl = process.env.DATABASE_URL;
95
+ if (!dbUrl || !dbUrl.startsWith("postgresql://")) {
96
+ errors.push("DATABASE_URL must be a valid PostgreSQL connection string");
97
+ }
98
+
99
+ if (errors.length > 0) {
100
+ throw new ConfigValidationError(errors);
101
+ }
102
+
103
+ return { port, dbUrl: dbUrl! };
104
+ }
105
+ ```
106
+
107
+ ### 5. Sanitize Before Processing
108
+ - Trim whitespace from string inputs
109
+ - Normalize Unicode (NFC) for text comparison
110
+ - Escape special characters for SQL, HTML, shell, and regex contexts
111
+ - Limit input length to prevent resource exhaustion
112
+
113
+ ### 6. Use Schema Validation Libraries
114
+ - Zod (TypeScript): composable schemas with type inference
115
+ - Pydantic (Python): model-based validation with automatic parsing
116
+ - joi / yup (JavaScript): mature schema validation
117
+ - Always derive TypeScript types from the schema, not the other way around
118
+
119
+ ```typescript
120
+ // Schema is the source of truth; type is derived
121
+ const userSchema = z.object({
122
+ name: z.string().min(1).max(200).trim(),
123
+ email: z.string().email().toLowerCase(),
124
+ age: z.number().int().min(0).max(150).optional(),
125
+ role: z.enum(["admin", "user", "viewer"]).default("user"),
126
+ });
127
+
128
+ type User = z.infer<typeof userSchema>; // Type derived from schema
129
+ ```
130
+
131
+ ## Test Accompaniment
132
+
133
+ ### 7. Generate Tests Alongside Code
134
+ - Every generated function should include at least one unit test
135
+ - Test the happy path, one edge case, and one error case at minimum
136
+ - Use descriptive test names that state the expected behavior
137
+
138
+ ```typescript
139
+ describe("calculateDiscount", () => {
140
+ it("should apply percentage discount to the subtotal", () => {
141
+ expect(calculateDiscount(100, { type: "percentage", value: 15 })).toBe(85);
142
+ });
143
+
144
+ it("should not reduce price below zero for large discounts", () => {
145
+ expect(calculateDiscount(10, { type: "fixed", value: 25 })).toBe(0);
146
+ });
147
+
148
+ it("should throw ValidationError for negative discount values", () => {
149
+ expect(() =>
150
+ calculateDiscount(100, { type: "percentage", value: -5 })
151
+ ).toThrow(ValidationError);
152
+ });
153
+ });
154
+ ```
155
+
156
+ ### 8. Test Structure: Arrange-Act-Assert
157
+ - **Arrange**: set up preconditions and inputs
158
+ - **Act**: execute the code under test
159
+ - **Assert**: verify the expected outcome
160
+ - Keep each test focused on a single behavior
161
+
162
+ ### 9. Test Error Paths Explicitly
163
+ - Verify that error messages are descriptive and actionable
164
+ - Verify that error types are correct (not just that an error was thrown)
165
+ - Test timeout behavior, retry logic, and graceful degradation
166
+
167
+ ```typescript
168
+ it("should throw NotFoundError with resource name and id", async () => {
169
+ await expect(userRepo.findById("nonexistent-id"))
170
+ .rejects
171
+ .toThrow(new NotFoundError("User", "nonexistent-id"));
172
+ });
173
+
174
+ it("should retry 3 times before throwing on transient failure", async () => {
175
+ const mockFn = jest.fn()
176
+ .mockRejectedValueOnce(new TransientError())
177
+ .mockRejectedValueOnce(new TransientError())
178
+ .mockRejectedValueOnce(new TransientError())
179
+ .mockResolvedValue("success");
180
+
181
+ await expect(withRetry(mockFn, { maxRetries: 2 })).rejects.toThrow(TransientError);
182
+ expect(mockFn).toHaveBeenCalledTimes(3);
183
+ });
184
+ ```
185
+
186
+ ## Code Organization
187
+
188
+ ### 10. Single Responsibility per Module
189
+ - Each file/module should have one clear purpose
190
+ - Group related types, functions, and constants together
191
+ - Keep files under 300 lines; split when complexity grows
192
+
193
+ ### 11. Explicit Exports
194
+ - Export only the public API; keep internals private
195
+ - Use barrel files (`index.ts`) to aggregate public exports
196
+ - Document exported functions with JSDoc or docstrings
197
+
198
+ ### 12. Consistent Naming Conventions
199
+ | Entity | Convention | Example |
200
+ |--------|-----------|---------|
201
+ | Functions | camelCase (JS/TS), snake_case (Python/Rust/Go) | `getUserById`, `get_user_by_id` |
202
+ | Classes/Types | PascalCase | `UserRepository`, `OrderStatus` |
203
+ | Constants | UPPER_SNAKE_CASE | `MAX_RETRY_COUNT`, `DEFAULT_TIMEOUT` |
204
+ | Boolean vars | is/has/can/should prefix | `isActive`, `hasPermission` |
205
+ | Files | kebab-case (JS/TS), snake_case (Python) | `user-repository.ts`, `user_repository.py` |
206
+
207
+ ## Documentation
208
+
209
+ ### 13. Self-Documenting Code with Strategic Comments
210
+ - Choose descriptive names that make code readable without comments
211
+ - Add comments for **why**, not **what** — explain non-obvious decisions
212
+ - Document public APIs with parameter descriptions, return types, and examples
213
+ - Include `@throws` / `Raises` annotations for functions that throw
214
+
215
+ ```typescript
216
+ /**
217
+ * Calculates the shipping cost based on package weight and destination zone.
218
+ *
219
+ * Uses a tiered pricing model: base rate + per-kg surcharge above the free tier.
220
+ * International zones (4+) include an additional customs processing fee.
221
+ *
222
+ * @param weightKg - Package weight in kilograms (must be > 0)
223
+ * @param zone - Destination shipping zone (1-6)
224
+ * @returns The total shipping cost in cents
225
+ * @throws {ValidationError} If weight is non-positive or zone is out of range
226
+ */
227
+ function calculateShippingCost(weightKg: number, zone: ShippingZone): number {
228
+ ```