cc-codeconductor 0.4.3 → 0.5.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/README.md +1 -1
- package/dist/index.js +2642 -226
- package/package.json +1 -1
- package/presets/agy/skills/evaluation/SKILL.md +6 -0
- package/presets/agy/skills/openspec/SKILL.md +32 -0
- package/presets/agy/workflows/cc-openspec.md +62 -0
- package/presets/agy/workflows/cc-scorecard.md +17 -0
- package/presets/claude/commands/cc/openspec.md +144 -0
- package/presets/claude/commands/cc/review.md +13 -2
- package/presets/claude/commands/cc/scorecard.md +65 -0
- package/presets/claude/skills/evaluation/SKILL.md +42 -0
- package/presets/claude/skills/openspec/SKILL.md +54 -0
- package/presets/codex/AGENTS.md +57 -0
- package/presets/cursor/.cursorignore +15 -0
- package/presets/cursor/AGENTS.md +504 -0
- package/presets/cursor/agents/architect.md +211 -0
- package/presets/cursor/agents/complexity-auditor.md +76 -0
- package/presets/cursor/agents/contract-builder.md +75 -0
- package/presets/cursor/agents/docs.md +180 -0
- package/presets/cursor/agents/goal-planner.md +71 -0
- package/presets/cursor/agents/implementer.md +161 -0
- package/presets/cursor/agents/orchestrator.md +377 -0
- package/presets/cursor/agents/repo-explorer.md +100 -0
- package/presets/cursor/agents/reviewer.md +237 -0
- package/presets/cursor/agents/security-reviewer.md +113 -0
- package/presets/cursor/agents/task-coach.md +145 -0
- package/presets/cursor/agents/tester.md +241 -0
- package/presets/cursor/commands/cc/api-contract.md +58 -0
- package/presets/cursor/commands/cc/db-migration.md +58 -0
- package/presets/cursor/commands/cc/feature.md +115 -0
- package/presets/cursor/commands/cc/fix.md +121 -0
- package/presets/cursor/commands/cc/openspec.md +144 -0
- package/presets/cursor/commands/cc/pagespeed.md +103 -0
- package/presets/cursor/commands/cc/refactor.md +148 -0
- package/presets/cursor/commands/cc/review.md +137 -0
- package/presets/cursor/commands/cc/scorecard.md +65 -0
- package/presets/cursor/commands/cc/tdd-cycle.md +226 -0
- package/presets/cursor/commands/cc/test-plan.md +138 -0
- package/presets/cursor/rules/behavioral-discipline.mdc +14 -0
- package/presets/cursor/rules/context-budget.mdc +12 -0
- package/presets/cursor/rules/orchestration.mdc +12 -0
- package/presets/cursor/rules/yagni-stdlib.mdc +11 -0
- package/presets/cursor/skills/android/SKILL.md +122 -0
- package/presets/cursor/skills/api-versioning/SKILL.md +394 -0
- package/presets/cursor/skills/astro/SKILL.md +322 -0
- package/presets/cursor/skills/auth-token-inspector/SKILL.md +33 -0
- package/presets/cursor/skills/code-review/SKILL.md +208 -0
- package/presets/cursor/skills/conductor-setup/SKILL.md +127 -0
- package/presets/cursor/skills/django-orm/SKILL.md +463 -0
- package/presets/cursor/skills/django-testing/SKILL.md +417 -0
- package/presets/cursor/skills/django-uv/SKILL.md +409 -0
- package/presets/cursor/skills/drizzle-schema-architect/SKILL.md +54 -0
- package/presets/cursor/skills/evaluation/SKILL.md +8 -0
- package/presets/cursor/skills/fastapi-pydantic-strict/SKILL.md +46 -0
- package/presets/cursor/skills/find-skills/SKILL.md +144 -0
- package/presets/cursor/skills/jpa-nplusone-detector/SKILL.md +49 -0
- package/presets/cursor/skills/jpa-postgres/SKILL.md +626 -0
- package/presets/cursor/skills/laravel-specialist/SKILL.md +267 -0
- package/presets/cursor/skills/laravel-specialist/references/eloquent.md +351 -0
- package/presets/cursor/skills/laravel-specialist/references/livewire.md +512 -0
- package/presets/cursor/skills/laravel-specialist/references/queues.md +423 -0
- package/presets/cursor/skills/laravel-specialist/references/routing.md +362 -0
- package/presets/cursor/skills/laravel-specialist/references/testing.md +522 -0
- package/presets/cursor/skills/livewire-alpine-bridge/SKILL.md +39 -0
- package/presets/cursor/skills/multi-agent-orchestration/README.md +144 -0
- package/presets/cursor/skills/multi-agent-orchestration/SKILL.md +579 -0
- package/presets/cursor/skills/multi-agent-orchestration/examples/framework_implementations.py +362 -0
- package/presets/cursor/skills/multi-agent-orchestration/examples/orchestration_patterns.py +411 -0
- package/presets/cursor/skills/multi-agent-orchestration/scripts/agent_communication.py +334 -0
- package/presets/cursor/skills/multi-agent-orchestration/scripts/benchmarking.py +341 -0
- package/presets/cursor/skills/multi-agent-orchestration/scripts/workflow_management.py +334 -0
- package/presets/cursor/skills/nextjs-typescript/SKILL.md +394 -0
- package/presets/cursor/skills/openspec/SKILL.md +52 -0
- package/presets/cursor/skills/pagespeed-insights/SKILL.md +445 -0
- package/presets/cursor/skills/pagespeed-insights/reference.md +50 -0
- package/presets/cursor/skills/pagespeed-perf/SKILL.md +281 -0
- package/presets/cursor/skills/php-pro/SKILL.md +210 -0
- package/presets/cursor/skills/php-pro/references/async-patterns.md +412 -0
- package/presets/cursor/skills/php-pro/references/laravel-patterns.md +377 -0
- package/presets/cursor/skills/php-pro/references/modern-php-features.md +323 -0
- package/presets/cursor/skills/php-pro/references/symfony-patterns.md +466 -0
- package/presets/cursor/skills/php-pro/references/testing-quality.md +466 -0
- package/presets/cursor/skills/python/SKILL.md +613 -0
- package/presets/cursor/skills/python-django-stack/SKILL.md +500 -0
- package/presets/cursor/skills/python-fastapi-stack/SKILL.md +464 -0
- package/presets/cursor/skills/security/SKILL.md +384 -0
- package/presets/cursor/skills/seo-analytics-injector/SKILL.md +44 -0
- package/presets/cursor/skills/spring-auth-auditor/SKILL.md +33 -0
- package/presets/cursor/skills/spring-boot-feature/SKILL.md +566 -0
- package/presets/cursor/skills/spring-boot-kotlin/SKILL.md +408 -0
- package/presets/cursor/skills/spring-boot-testing-strategy/SKILL.md +479 -0
- package/presets/cursor/skills/sqlalchemy/SKILL.md +473 -0
- package/presets/cursor/skills/tailwind-responsive-auditor/SKILL.md +32 -0
- package/presets/cursor/skills/tdd-mutation-tester/SKILL.md +28 -0
- package/presets/cursor/skills/testing-tdd/SKILL.md +592 -0
- package/presets/cursor/skills/workflow-orchestration-patterns/SKILL.md +98 -0
- package/presets/cursor/skills/workflow-orchestration-patterns/references/details.md +223 -0
- package/presets/opencode/agents/architect.md +1 -2
- package/presets/opencode/agents/complexity-auditor.md +1 -0
- package/presets/opencode/agents/contract-builder.md +93 -0
- package/presets/opencode/agents/docs.md +1 -2
- package/presets/opencode/agents/goal-planner.md +82 -0
- package/presets/opencode/agents/implementer.md +9 -2
- package/presets/opencode/agents/orchestrator.md +50 -12
- package/presets/opencode/agents/repo-explorer.md +0 -1
- package/presets/opencode/agents/reviewer.md +23 -2
- package/presets/opencode/agents/security-reviewer.md +129 -0
- package/presets/opencode/agents/task-coach.md +1 -2
- package/presets/opencode/agents/tester.md +1 -2
- package/presets/opencode/commands/cc-openspec.md +61 -0
- package/presets/opencode/commands/cc-scorecard.md +16 -0
- package/presets/opencode/prompts/v0.5.0/architect.md +222 -0
- package/presets/opencode/prompts/v0.5.0/complexity-auditor.md +91 -0
- package/presets/opencode/prompts/v0.5.0/contract-builder.md +84 -0
- package/presets/opencode/prompts/v0.5.0/docs.md +190 -0
- package/presets/opencode/prompts/v0.5.0/goal-planner.md +80 -0
- package/presets/opencode/prompts/v0.5.0/implementer.md +171 -0
- package/presets/opencode/prompts/v0.5.0/orchestrator.md +388 -0
- package/presets/opencode/prompts/v0.5.0/repo-explorer.md +111 -0
- package/presets/opencode/prompts/v0.5.0/reviewer.md +248 -0
- package/presets/opencode/prompts/v0.5.0/security-reviewer.md +123 -0
- package/presets/opencode/prompts/v0.5.0/task-coach.md +156 -0
- package/presets/opencode/prompts/v0.5.0/tester.md +252 -0
- package/presets/opencode/skills/evaluation/SKILL.md +6 -0
- package/presets/opencode/skills/openspec/SKILL.md +50 -0
- package/presets/templates/BACKLOG.md +33 -0
- package/presets/templates/execution-profile.yml +6 -0
- package/presets/templates/model-comparison.md +11 -0
- package/presets/templates/regression-checklist.yml +10 -0
- package/src/presets/manifests/agy.yml +2 -2
- package/src/presets/manifests/claude.yml +2 -2
- package/src/presets/manifests/codex.yml +2 -2
- package/src/presets/manifests/cursor.yml +19 -3
- package/src/presets/manifests/gemini.yml +2 -2
- package/src/presets/manifests/opencode.yml +2 -2
- package/src/presets/models/agy.yml +21 -0
- package/src/presets/models/claude.yml +18 -0
- package/src/presets/models/codex.yml +18 -0
- package/src/presets/models/cursor.yml +39 -9
- package/src/presets/models/gemini.yml +18 -0
- package/src/presets/models/opencode.yml +18 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: nextjs-typescript
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
name: Next.js + TypeScript
|
|
5
|
+
description: >
|
|
6
|
+
Provides expert knowledge for building Next.js 15+ applications with the App Router, TypeScript, Server Components, Server Actions, and TanStack Query.
|
|
7
|
+
|
|
8
|
+
user-invokable: true
|
|
9
|
+
license: MIT
|
|
10
|
+
metadata:
|
|
11
|
+
author: lgzarturo
|
|
12
|
+
category: frontend
|
|
13
|
+
|
|
14
|
+
compatibility:
|
|
15
|
+
tools: [claude, codex, gemini, agy, opencode]
|
|
16
|
+
stacks:
|
|
17
|
+
languages: []
|
|
18
|
+
frameworks: []
|
|
19
|
+
|
|
20
|
+
risk:
|
|
21
|
+
level: medium
|
|
22
|
+
can_execute_shell: false
|
|
23
|
+
can_modify_files: true
|
|
24
|
+
requires_network: false
|
|
25
|
+
|
|
26
|
+
inputs: []
|
|
27
|
+
|
|
28
|
+
outputs: []
|
|
29
|
+
|
|
30
|
+
quality:
|
|
31
|
+
reviewed_by: codeconductor-core
|
|
32
|
+
version: 0.1.0
|
|
33
|
+
paths:
|
|
34
|
+
- "**/*.{ts,tsx}"
|
|
35
|
+
- "**/next.config.*"
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# Next.js + TypeScript
|
|
41
|
+
|
|
42
|
+
## Server vs Client Components
|
|
43
|
+
|
|
44
|
+
The App Router defaults to Server Components. Every component is a Server
|
|
45
|
+
Component unless it explicitly opts in to the client.
|
|
46
|
+
|
|
47
|
+
### Decision Rule
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
Does the component need any of the following?
|
|
51
|
+
- useState / useReducer
|
|
52
|
+
- useEffect / lifecycle methods
|
|
53
|
+
- Browser APIs (window, document, localStorage)
|
|
54
|
+
- Event listeners (onClick, onChange, onSubmit)
|
|
55
|
+
- Third-party libraries that require the DOM
|
|
56
|
+
|
|
57
|
+
YES → Client Component (`"use client"` directive)
|
|
58
|
+
NO → Server Component (default, no directive needed)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Keep the `"use client"` boundary as far down the component tree as possible.
|
|
62
|
+
Wrap only the interactive leaf node, not the entire page.
|
|
63
|
+
|
|
64
|
+
### Server Component (default)
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
// app/users/page.tsx — no directive needed
|
|
68
|
+
import { db } from '@/lib/db';
|
|
69
|
+
|
|
70
|
+
export default async function UsersPage() {
|
|
71
|
+
// Direct database access — no API round-trip needed
|
|
72
|
+
const users = await db.user.findMany({ orderBy: { createdAt: 'desc' } });
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<ul>
|
|
76
|
+
{users.map(user => (
|
|
77
|
+
<li key={user.id}>{user.email}</li>
|
|
78
|
+
))}
|
|
79
|
+
</ul>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Client Component
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
// components/ui/counter.tsx
|
|
88
|
+
'use client';
|
|
89
|
+
|
|
90
|
+
import { useState } from 'react';
|
|
91
|
+
|
|
92
|
+
interface Props {
|
|
93
|
+
initialCount?: number;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function Counter({ initialCount = 0 }: Props) {
|
|
97
|
+
const [count, setCount] = useState(initialCount);
|
|
98
|
+
return <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>;
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Composing Server and Client
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
// app/dashboard/page.tsx — Server Component
|
|
106
|
+
import { Counter } from '@/components/ui/counter'; // Client
|
|
107
|
+
import { getUser } from '@/lib/queries'; // Server-only function
|
|
108
|
+
|
|
109
|
+
export default async function DashboardPage() {
|
|
110
|
+
const user = await getUser(); // runs on the server
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div>
|
|
114
|
+
<h1>Welcome, {user.name}</h1>
|
|
115
|
+
<Counter initialCount={user.loginCount} /> {/* client island */}
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Passing server data to client components as props is correct. The server
|
|
122
|
+
renders the Server Component tree first, serializes the props, and sends them
|
|
123
|
+
to the client.
|
|
124
|
+
|
|
125
|
+
## Data Fetching
|
|
126
|
+
|
|
127
|
+
### Server Component Fetching (recommended for initial data)
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
// app/posts/[id]/page.tsx
|
|
131
|
+
interface Props {
|
|
132
|
+
params: Promise<{ id: string }>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export default async function PostPage({ params }: Props) {
|
|
136
|
+
const { id } = await params;
|
|
137
|
+
const post = await fetch(`https://api.example.com/posts/${id}`, {
|
|
138
|
+
next: { revalidate: 3600 }, // ISR: revalidate every hour
|
|
139
|
+
}).then(r => r.json());
|
|
140
|
+
|
|
141
|
+
if (!post) notFound();
|
|
142
|
+
|
|
143
|
+
return <article>{post.title}</article>;
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Cache strategies:
|
|
148
|
+
|
|
149
|
+
| `cache` option | Behavior |
|
|
150
|
+
|----------------|----------|
|
|
151
|
+
| `force-cache` | Cache indefinitely (default for fetch in RSC) |
|
|
152
|
+
| `no-store` | Never cache — fresh on every request |
|
|
153
|
+
| `next: { revalidate: N }` | ISR — revalidate after N seconds |
|
|
154
|
+
| `next: { tags: ['posts'] }` | On-demand revalidation via tag |
|
|
155
|
+
|
|
156
|
+
### Server Actions (mutations)
|
|
157
|
+
|
|
158
|
+
Server Actions run on the server. Use them for form submissions and mutations.
|
|
159
|
+
Never use them for reads.
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
// app/posts/create/actions.ts
|
|
163
|
+
'use server';
|
|
164
|
+
|
|
165
|
+
import { revalidatePath } from 'next/cache';
|
|
166
|
+
import { redirect } from 'next/navigation';
|
|
167
|
+
import { z } from 'zod';
|
|
168
|
+
import { db } from '@/lib/db';
|
|
169
|
+
|
|
170
|
+
const CreatePostSchema = z.object({
|
|
171
|
+
title: z.string().min(1).max(200),
|
|
172
|
+
content: z.string().min(1),
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
export async function createPost(formData: FormData) {
|
|
176
|
+
const parsed = CreatePostSchema.safeParse({
|
|
177
|
+
title: formData.get('title'),
|
|
178
|
+
content: formData.get('content'),
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
if (!parsed.success) {
|
|
182
|
+
return { error: parsed.error.flatten().fieldErrors };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
await db.post.create({ data: parsed.data });
|
|
186
|
+
|
|
187
|
+
revalidatePath('/posts');
|
|
188
|
+
redirect('/posts');
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
// app/posts/create/page.tsx
|
|
194
|
+
import { createPost } from './actions';
|
|
195
|
+
|
|
196
|
+
export default function CreatePostPage() {
|
|
197
|
+
return (
|
|
198
|
+
<form action={createPost}>
|
|
199
|
+
<input name="title" type="text" required />
|
|
200
|
+
<textarea name="content" required />
|
|
201
|
+
<button type="submit">Create</button>
|
|
202
|
+
</form>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Rules for Server Actions:
|
|
208
|
+
|
|
209
|
+
- Always validate input with Zod — do not trust `FormData` values
|
|
210
|
+
- Return error objects for validation failures; use `redirect()` for success
|
|
211
|
+
- Call `revalidatePath()` or `revalidateTag()` after mutations that affect
|
|
212
|
+
cached data
|
|
213
|
+
- Never put secrets or auth logic in Client Components — keep it in actions
|
|
214
|
+
|
|
215
|
+
### TanStack Query (client-side data)
|
|
216
|
+
|
|
217
|
+
Use TanStack Query for data that must stay fresh on the client: real-time
|
|
218
|
+
feeds, user-specific data after mutations, optimistic updates.
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
// components/posts/post-list.tsx
|
|
222
|
+
'use client';
|
|
223
|
+
|
|
224
|
+
import { useQuery } from '@tanstack/react-query';
|
|
225
|
+
|
|
226
|
+
interface Post {
|
|
227
|
+
id: string;
|
|
228
|
+
title: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function PostList() {
|
|
232
|
+
const { data, isLoading, error } = useQuery<Post[]>({
|
|
233
|
+
queryKey: ['posts'],
|
|
234
|
+
queryFn: () => fetch('/api/posts').then(r => r.json()),
|
|
235
|
+
staleTime: 60_000, // treat data as fresh for 60 seconds
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
if (isLoading) return <p>Loading...</p>;
|
|
239
|
+
if (error) return <p>Failed to load posts.</p>;
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<ul>
|
|
243
|
+
{data?.map(post => <li key={post.id}>{post.title}</li>)}
|
|
244
|
+
</ul>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Do not use TanStack Query for data that a Server Component can fetch directly.
|
|
250
|
+
The extra client-side fetch is unnecessary when the data can be fetched at
|
|
251
|
+
render time on the server.
|
|
252
|
+
|
|
253
|
+
## Route Handlers
|
|
254
|
+
|
|
255
|
+
Use route handlers for: webhooks, third-party OAuth callbacks, or endpoints
|
|
256
|
+
consumed by non-Next.js clients.
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
// app/api/posts/route.ts
|
|
260
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
261
|
+
import { z } from 'zod';
|
|
262
|
+
import { db } from '@/lib/db';
|
|
263
|
+
|
|
264
|
+
const CreatePostBody = z.object({
|
|
265
|
+
title: z.string().min(1),
|
|
266
|
+
content: z.string().min(1),
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
export async function GET() {
|
|
270
|
+
const posts = await db.post.findMany({ orderBy: { createdAt: 'desc' } });
|
|
271
|
+
return NextResponse.json(posts);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export async function POST(request: NextRequest) {
|
|
275
|
+
const body = await request.json();
|
|
276
|
+
const parsed = CreatePostBody.safeParse(body);
|
|
277
|
+
|
|
278
|
+
if (!parsed.success) {
|
|
279
|
+
return NextResponse.json(
|
|
280
|
+
{ error: parsed.error.flatten() },
|
|
281
|
+
{ status: 400 }
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const post = await db.post.create({ data: parsed.data });
|
|
286
|
+
return NextResponse.json(post, { status: 201 });
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Metadata API
|
|
291
|
+
|
|
292
|
+
```tsx
|
|
293
|
+
// app/posts/[id]/page.tsx
|
|
294
|
+
import type { Metadata } from 'next';
|
|
295
|
+
|
|
296
|
+
interface Props {
|
|
297
|
+
params: Promise<{ id: string }>;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|
301
|
+
const { id } = await params;
|
|
302
|
+
const post = await fetch(`/api/posts/${id}`).then(r => r.json());
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
title: post.title,
|
|
306
|
+
description: post.excerpt,
|
|
307
|
+
openGraph: {
|
|
308
|
+
title: post.title,
|
|
309
|
+
images: [{ url: post.coverImage }],
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Never hardcode metadata in `<head>` tags — use the Metadata API. It handles
|
|
316
|
+
deduplication, inheritance, and streaming correctly.
|
|
317
|
+
|
|
318
|
+
## Streaming with Suspense
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
// app/dashboard/page.tsx
|
|
322
|
+
import { Suspense } from 'react';
|
|
323
|
+
import { UserStats } from './user-stats'; // slow data fetch
|
|
324
|
+
import { RecentActivity } from './recent'; // fast data fetch
|
|
325
|
+
|
|
326
|
+
export default function DashboardPage() {
|
|
327
|
+
return (
|
|
328
|
+
<div>
|
|
329
|
+
<RecentActivity /> {/* renders immediately */}
|
|
330
|
+
<Suspense fallback={<p>Loading stats...</p>}>
|
|
331
|
+
<UserStats /> {/* streams in when ready */}
|
|
332
|
+
</Suspense>
|
|
333
|
+
</div>
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Wrap independently slow data sources in their own `<Suspense>` boundaries.
|
|
339
|
+
Do not wrap the entire page — that defeats streaming.
|
|
340
|
+
|
|
341
|
+
## TypeScript Conventions
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
// Use type imports for type-only imports
|
|
345
|
+
import type { User } from '@prisma/client';
|
|
346
|
+
|
|
347
|
+
// Prefer interfaces for object shapes that may be extended
|
|
348
|
+
interface UserCardProps {
|
|
349
|
+
user: Pick<User, 'id' | 'name' | 'email'>;
|
|
350
|
+
onSelect?: (id: string) => void;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Use type aliases for unions and computed types
|
|
354
|
+
type Status = 'active' | 'inactive' | 'pending';
|
|
355
|
+
type UserWithPosts = User & { posts: Post[] };
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Rules:
|
|
359
|
+
|
|
360
|
+
- Never use `any` — use `unknown` and narrow with type guards
|
|
361
|
+
- Use `satisfies` to validate objects against a type without widening
|
|
362
|
+
- Co-locate type definitions with the component or function that uses them;
|
|
363
|
+
export only what other modules need
|
|
364
|
+
- Use `next/navigation` hooks (`useRouter`, `usePathname`) not `next/router` —
|
|
365
|
+
the latter is Pages Router only
|
|
366
|
+
|
|
367
|
+
## Project Structure
|
|
368
|
+
|
|
369
|
+
```text
|
|
370
|
+
app/
|
|
371
|
+
(auth)/ — route group, no URL segment
|
|
372
|
+
login/page.tsx
|
|
373
|
+
register/page.tsx
|
|
374
|
+
(dashboard)/
|
|
375
|
+
dashboard/page.tsx
|
|
376
|
+
posts/
|
|
377
|
+
[id]/page.tsx
|
|
378
|
+
create/
|
|
379
|
+
page.tsx
|
|
380
|
+
actions.ts
|
|
381
|
+
api/
|
|
382
|
+
posts/route.ts
|
|
383
|
+
layout.tsx — root layout
|
|
384
|
+
not-found.tsx
|
|
385
|
+
|
|
386
|
+
components/
|
|
387
|
+
ui/ — generic, reusable components
|
|
388
|
+
posts/ — domain-specific components
|
|
389
|
+
|
|
390
|
+
lib/
|
|
391
|
+
db.ts — database client
|
|
392
|
+
auth.ts — auth configuration
|
|
393
|
+
queries.ts — reusable server-side query functions
|
|
394
|
+
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openspec
|
|
3
|
+
description:
|
|
4
|
+
OpenSpec backlog format, state machine, and delivery workflow for CodeConductor.
|
|
5
|
+
Use when running /cc-openspec or editing BACKLOG.md.
|
|
6
|
+
|
|
7
|
+
disable-model-invocation: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# OpenSpec / BACKLOG Skill
|
|
11
|
+
|
|
12
|
+
## BACKLOG.md contract
|
|
13
|
+
|
|
14
|
+
`BACKLOG.md` at repo root is the operational queue. Required sections:
|
|
15
|
+
|
|
16
|
+
- `## Global` — Product, Strategy, Policy, Review required, TDD required
|
|
17
|
+
- `## Items` — active backlog entries
|
|
18
|
+
- `## Archive` — completed entries (do not re-execute)
|
|
19
|
+
|
|
20
|
+
Each item: `### BC-001 | Short title` with Priority (P0–P3), Status, Type, Depends on, Description, Scope, Out of scope, Acceptance (measurable checklist).
|
|
21
|
+
|
|
22
|
+
## Status machine
|
|
23
|
+
|
|
24
|
+
`TODO` → `READY` → `PLANNED` → `IN_PROGRESS` → `REVIEW` → `DONE` → Archive
|
|
25
|
+
|
|
26
|
+
`BLOCKED` can return to `READY` when resolved. Reviewer rejection: `REVIEW` → `IN_PROGRESS`.
|
|
27
|
+
|
|
28
|
+
## CLI commands
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx cc-codeconductor openspec validate
|
|
32
|
+
npx cc-codeconductor openspec scan
|
|
33
|
+
npx cc-codeconductor openspec plan BC-001
|
|
34
|
+
npx cc-codeconductor openspec status
|
|
35
|
+
npx cc-codeconductor openspec next
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## OpenSpec folders
|
|
39
|
+
|
|
40
|
+
Each item generates `openspec/changes/<slug>/` with `proposal.md`, `design.md`, `tasks.md`, `specs/`.
|
|
41
|
+
|
|
42
|
+
## Agent phases
|
|
43
|
+
|
|
44
|
+
| Phase | Agent |
|
|
45
|
+
|-------|-------|
|
|
46
|
+
| discover | repo-explorer |
|
|
47
|
+
| design | architect |
|
|
48
|
+
| test | tester |
|
|
49
|
+
| implement | implementer |
|
|
50
|
+
| review | reviewer |
|
|
51
|
+
|
|
52
|
+
When Global `TDD required: yes`, test runs before implement.
|