catalyst-os 3.0.2 → 3.1.1
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/.catalyst/bin/install.js +9 -0
- package/.catalyst/main/temp/temp-architecture.md +188 -0
- package/.catalyst/main/temp/temp-concerns.md +225 -0
- package/.catalyst/main/temp/temp-conventions.md +321 -0
- package/.catalyst/main/temp/temp-dashboard.html +380 -0
- package/.catalyst/main/temp/temp-mission.md +65 -0
- package/.catalyst/main/temp/temp-roadmap.md +166 -0
- package/.catalyst/main/temp/temp-tech-stack.md +165 -0
- package/.claude/agents/curator.md +1 -1
- package/.claude/commands/plan-project.md +75 -0
- package/.claude/skills/build-orchestration/SKILL.md +4 -0
- package/.claude/skills/project-initialization/SKILL.md +10 -1
- package/.claude/skills/project-sync/SKILL.md +13 -4
- package/.claude/skills/spec-approval/SKILL.md +4 -0
- package/.claude/skills/spec-archival/SKILL.md +4 -0
- package/.claude/skills/spec-lifecycle-board/SKILL.md +73 -0
- package/.claude/skills/spec-shaping/SKILL.md +4 -0
- package/.claude/skills/spec-validation/SKILL.md +4 -0
- package/.claude/skills/using-skills/SKILL.md +1 -0
- package/README.md +26 -1
- package/package.json +2 -1
- package/.claude/commands/roadmap.md +0 -69
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# Conventions
|
|
2
|
+
|
|
3
|
+
> Analysis Date: YYYY-MM-DD
|
|
4
|
+
> Update when: New patterns established, tooling changes
|
|
5
|
+
|
|
6
|
+
## Naming Conventions
|
|
7
|
+
|
|
8
|
+
### Files & Directories
|
|
9
|
+
|
|
10
|
+
| Type | Convention | Example |
|
|
11
|
+
|------|------------|---------|
|
|
12
|
+
| Components | PascalCase | `UserProfile.tsx` |
|
|
13
|
+
| Hooks | camelCase with `use` prefix | `useAuth.ts` |
|
|
14
|
+
| Utilities | camelCase | `formatDate.ts` |
|
|
15
|
+
| Constants | SCREAMING_SNAKE | `constants.ts` → `MAX_RETRIES` |
|
|
16
|
+
| Types | PascalCase | `types.ts` → `User`, `CreateUserInput` |
|
|
17
|
+
| API routes | kebab-case | `api/user-settings/route.ts` |
|
|
18
|
+
| Test files | Same as source + `.test` | `UserProfile.test.tsx` |
|
|
19
|
+
|
|
20
|
+
### Variables & Functions
|
|
21
|
+
|
|
22
|
+
| Type | Convention | Example |
|
|
23
|
+
|------|------------|---------|
|
|
24
|
+
| Variables | camelCase | `const userName = ...` |
|
|
25
|
+
| Functions | camelCase, verb prefix | `getUserById()`, `createOrder()` |
|
|
26
|
+
| Booleans | `is`/`has`/`should` prefix | `isLoading`, `hasError` |
|
|
27
|
+
| Event handlers | `handle` + event | `handleClick`, `handleSubmit` |
|
|
28
|
+
| Callbacks | `on` + event | `onClick`, `onSuccess` |
|
|
29
|
+
|
|
30
|
+
### React Components
|
|
31
|
+
|
|
32
|
+
| Type | Convention | Example |
|
|
33
|
+
|------|------------|---------|
|
|
34
|
+
| Component name | PascalCase | `UserProfile` |
|
|
35
|
+
| Props interface | `ComponentNameProps` | `UserProfileProps` |
|
|
36
|
+
| Context | `ContextName` + `Provider` | `AuthContext`, `AuthProvider` |
|
|
37
|
+
| Custom hooks | `use` + noun | `useUser`, `useAuth` |
|
|
38
|
+
|
|
39
|
+
### Database
|
|
40
|
+
|
|
41
|
+
| Type | Convention | Example |
|
|
42
|
+
|------|------------|---------|
|
|
43
|
+
| Tables | snake_case, plural | `users`, `order_items` |
|
|
44
|
+
| Columns | snake_case | `created_at`, `user_id` |
|
|
45
|
+
| Foreign keys | `referenced_table_id` | `user_id`, `order_id` |
|
|
46
|
+
| Indexes | `idx_table_columns` | `idx_users_email` |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Code Organization
|
|
51
|
+
|
|
52
|
+
### Import Order
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// 1. External libraries
|
|
56
|
+
import { useState } from 'react';
|
|
57
|
+
import { z } from 'zod';
|
|
58
|
+
|
|
59
|
+
// 2. Internal aliases (@/)
|
|
60
|
+
import { Button } from '@/components/ui';
|
|
61
|
+
import { useAuth } from '@/hooks';
|
|
62
|
+
|
|
63
|
+
// 3. Relative imports
|
|
64
|
+
import { UserAvatar } from './UserAvatar';
|
|
65
|
+
import type { UserProfileProps } from './types';
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### File Structure (Components)
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
src/components/UserProfile/
|
|
72
|
+
├── index.ts # Re-export
|
|
73
|
+
├── UserProfile.tsx # Main component
|
|
74
|
+
├── UserProfile.test.tsx # Tests
|
|
75
|
+
├── UserAvatar.tsx # Sub-component
|
|
76
|
+
└── types.ts # Types (if complex)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Export Patterns
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// Named exports for utilities
|
|
83
|
+
export function formatDate(date: Date): string { ... }
|
|
84
|
+
export function formatCurrency(amount: number): string { ... }
|
|
85
|
+
|
|
86
|
+
// Default export for components
|
|
87
|
+
export default function UserProfile({ user }: UserProfileProps) { ... }
|
|
88
|
+
|
|
89
|
+
// Barrel exports in index.ts
|
|
90
|
+
export { UserProfile } from './UserProfile';
|
|
91
|
+
export { UserAvatar } from './UserAvatar';
|
|
92
|
+
export type { UserProfileProps } from './types';
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Formatting Standards
|
|
98
|
+
|
|
99
|
+
### General
|
|
100
|
+
|
|
101
|
+
| Rule | Standard |
|
|
102
|
+
|------|----------|
|
|
103
|
+
| Indentation | 2 spaces |
|
|
104
|
+
| Line length | 100 characters max |
|
|
105
|
+
| Quotes | Single quotes for JS/TS |
|
|
106
|
+
| Semicolons | [Yes / No] |
|
|
107
|
+
| Trailing commas | ES5 (objects, arrays) |
|
|
108
|
+
|
|
109
|
+
### TypeScript
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// Prefer interfaces for objects
|
|
113
|
+
interface User {
|
|
114
|
+
id: string;
|
|
115
|
+
name: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Use type for unions, primitives
|
|
119
|
+
type Status = 'active' | 'inactive';
|
|
120
|
+
type UserId = string;
|
|
121
|
+
|
|
122
|
+
// Explicit return types on exports
|
|
123
|
+
export function getUser(id: string): Promise<User | null> { ... }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### React/JSX
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
// Multi-line props (3+ props)
|
|
130
|
+
<Button
|
|
131
|
+
variant="primary"
|
|
132
|
+
size="lg"
|
|
133
|
+
onClick={handleClick}
|
|
134
|
+
>
|
|
135
|
+
Submit
|
|
136
|
+
</Button>
|
|
137
|
+
|
|
138
|
+
// Single line (1-2 props)
|
|
139
|
+
<Button variant="primary" onClick={handleClick}>Submit</Button>
|
|
140
|
+
|
|
141
|
+
// Self-closing tags
|
|
142
|
+
<Input placeholder="Enter name" />
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Error Handling
|
|
148
|
+
|
|
149
|
+
### Creating Errors
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// src/lib/errors.ts
|
|
153
|
+
export class AppError extends Error {
|
|
154
|
+
constructor(
|
|
155
|
+
public code: string,
|
|
156
|
+
message: string,
|
|
157
|
+
public statusCode: number = 500
|
|
158
|
+
) {
|
|
159
|
+
super(message);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export class NotFoundError extends AppError {
|
|
164
|
+
constructor(resource: string) {
|
|
165
|
+
super('NOT_FOUND', `${resource} not found`, 404);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Throwing Errors
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
// In services
|
|
174
|
+
if (!user) {
|
|
175
|
+
throw new NotFoundError('User');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// In API routes
|
|
179
|
+
try {
|
|
180
|
+
const result = await service.doSomething();
|
|
181
|
+
return Response.json(result);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
return handleError(error);
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Error Response Format
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"error": {
|
|
192
|
+
"code": "NOT_FOUND",
|
|
193
|
+
"message": "User not found",
|
|
194
|
+
"details": {}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Testing Conventions
|
|
202
|
+
|
|
203
|
+
### File Naming
|
|
204
|
+
|
|
205
|
+
| Test Type | Location | Naming |
|
|
206
|
+
|-----------|----------|--------|
|
|
207
|
+
| Unit tests | Next to source | `*.test.ts` |
|
|
208
|
+
| Integration | `tests/integration/` | `*.integration.test.ts` |
|
|
209
|
+
| E2E | `tests/e2e/` | `*.e2e.test.ts` |
|
|
210
|
+
|
|
211
|
+
### Test Structure
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
describe('UserService', () => {
|
|
215
|
+
describe('getUser', () => {
|
|
216
|
+
it('should return user when found', async () => {
|
|
217
|
+
// Arrange
|
|
218
|
+
const userId = 'user-123';
|
|
219
|
+
mockDb.user.findUnique.mockResolvedValue(mockUser);
|
|
220
|
+
|
|
221
|
+
// Act
|
|
222
|
+
const result = await userService.getUser(userId);
|
|
223
|
+
|
|
224
|
+
// Assert
|
|
225
|
+
expect(result).toEqual(mockUser);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('should throw NotFoundError when user not found', async () => {
|
|
229
|
+
// Arrange
|
|
230
|
+
mockDb.user.findUnique.mockResolvedValue(null);
|
|
231
|
+
|
|
232
|
+
// Act & Assert
|
|
233
|
+
await expect(userService.getUser('invalid')).rejects.toThrow(NotFoundError);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Mocking
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
// Mock setup
|
|
243
|
+
jest.mock('@/lib/db');
|
|
244
|
+
const mockDb = db as jest.Mocked<typeof db>;
|
|
245
|
+
|
|
246
|
+
// Reset between tests
|
|
247
|
+
beforeEach(() => {
|
|
248
|
+
jest.clearAllMocks();
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Comments & Documentation
|
|
255
|
+
|
|
256
|
+
### When to Comment
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
// DO: Explain WHY, not WHAT
|
|
260
|
+
// Using setTimeout to debounce rapid clicks and prevent duplicate submissions
|
|
261
|
+
const debouncedSubmit = debounce(handleSubmit, 300);
|
|
262
|
+
|
|
263
|
+
// DON'T: Obvious comments
|
|
264
|
+
// Get the user by ID
|
|
265
|
+
const user = await getUser(id);
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### JSDoc for Public APIs
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
/**
|
|
272
|
+
* Creates a new user account
|
|
273
|
+
* @param data - User registration data
|
|
274
|
+
* @returns The created user (without password)
|
|
275
|
+
* @throws {ValidationError} If email is already taken
|
|
276
|
+
*/
|
|
277
|
+
export async function createUser(data: CreateUserInput): Promise<User> {
|
|
278
|
+
...
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### TODO Format
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// TODO(username): Description of what needs to be done
|
|
286
|
+
// TODO: Short description for anonymous todos
|
|
287
|
+
// FIXME: Known bug that needs fixing
|
|
288
|
+
// HACK: Workaround that should be improved
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Git Conventions
|
|
294
|
+
|
|
295
|
+
### Branch Naming
|
|
296
|
+
|
|
297
|
+
| Type | Format | Example |
|
|
298
|
+
|------|--------|---------|
|
|
299
|
+
| Feature | `feature/description` | `feature/user-auth` |
|
|
300
|
+
| Bug fix | `fix/description` | `fix/login-redirect` |
|
|
301
|
+
| Spec work | `spec/YYYY-MM-DD-slug` | `spec/2025-01-11-auth` |
|
|
302
|
+
| Task work | `task/YYYY-MM-DD-slug` | `task/2025-01-15-timeout` |
|
|
303
|
+
|
|
304
|
+
### Commit Messages
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
type(scope): description
|
|
308
|
+
|
|
309
|
+
type: feat, fix, docs, style, refactor, test, chore
|
|
310
|
+
scope: optional, component/area affected
|
|
311
|
+
description: imperative mood, lowercase, no period
|
|
312
|
+
|
|
313
|
+
Examples:
|
|
314
|
+
feat(auth): add password reset flow
|
|
315
|
+
fix(api): handle null user in profile endpoint
|
|
316
|
+
docs: update README with setup instructions
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
*Last updated: YYYY-MM-DD*
|