@girardmedia/bootspring 1.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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +255 -0
  3. package/agents/README.md +93 -0
  4. package/agents/api-expert/context.md +416 -0
  5. package/agents/architecture-expert/context.md +454 -0
  6. package/agents/backend-expert/context.md +483 -0
  7. package/agents/code-review-expert/context.md +365 -0
  8. package/agents/database-expert/context.md +250 -0
  9. package/agents/devops-expert/context.md +446 -0
  10. package/agents/frontend-expert/context.md +364 -0
  11. package/agents/index.js +140 -0
  12. package/agents/performance-expert/context.md +377 -0
  13. package/agents/security-expert/context.md +343 -0
  14. package/agents/testing-expert/context.md +414 -0
  15. package/agents/ui-ux-expert/context.md +448 -0
  16. package/agents/vercel-expert/context.md +426 -0
  17. package/bin/bootspring.js +310 -0
  18. package/cli/agent.js +337 -0
  19. package/cli/context.js +194 -0
  20. package/cli/dashboard.js +150 -0
  21. package/cli/generate.js +294 -0
  22. package/cli/init.js +410 -0
  23. package/cli/loop.js +421 -0
  24. package/cli/mcp.js +241 -0
  25. package/cli/memory.js +303 -0
  26. package/cli/orchestrator.js +400 -0
  27. package/cli/plugin.js +451 -0
  28. package/cli/quality.js +332 -0
  29. package/cli/skill.js +369 -0
  30. package/cli/task.js +628 -0
  31. package/cli/telemetry.js +114 -0
  32. package/cli/todo.js +614 -0
  33. package/cli/update.js +312 -0
  34. package/core/config.js +245 -0
  35. package/core/context.js +329 -0
  36. package/core/entitlements.js +209 -0
  37. package/core/index.js +43 -0
  38. package/core/policies.js +68 -0
  39. package/core/telemetry.js +247 -0
  40. package/core/utils.js +380 -0
  41. package/dashboard/server.js +818 -0
  42. package/docs/integrations/claude-code.md +42 -0
  43. package/docs/integrations/codex.md +42 -0
  44. package/docs/mcp-api-platform.md +102 -0
  45. package/generators/generate.js +598 -0
  46. package/generators/index.js +18 -0
  47. package/hooks/context-detector.js +177 -0
  48. package/hooks/index.js +35 -0
  49. package/hooks/prompt-enhancer.js +289 -0
  50. package/intelligence/git-memory.js +551 -0
  51. package/intelligence/index.js +59 -0
  52. package/intelligence/orchestrator.js +964 -0
  53. package/intelligence/prd.js +447 -0
  54. package/intelligence/recommendation-weights.json +18 -0
  55. package/intelligence/recommendations.js +234 -0
  56. package/mcp/capabilities.js +71 -0
  57. package/mcp/contracts/mcp-contract.v1.json +497 -0
  58. package/mcp/registry.js +213 -0
  59. package/mcp/response-formatter.js +462 -0
  60. package/mcp/server.js +99 -0
  61. package/mcp/tools/agent-tool.js +137 -0
  62. package/mcp/tools/capabilities-tool.js +54 -0
  63. package/mcp/tools/context-tool.js +49 -0
  64. package/mcp/tools/dashboard-tool.js +58 -0
  65. package/mcp/tools/generate-tool.js +46 -0
  66. package/mcp/tools/loop-tool.js +134 -0
  67. package/mcp/tools/memory-tool.js +180 -0
  68. package/mcp/tools/orchestrator-tool.js +232 -0
  69. package/mcp/tools/plugin-tool.js +76 -0
  70. package/mcp/tools/quality-tool.js +47 -0
  71. package/mcp/tools/skill-tool.js +233 -0
  72. package/mcp/tools/telemetry-tool.js +95 -0
  73. package/mcp/tools/todo-tool.js +133 -0
  74. package/package.json +98 -0
  75. package/plugins/index.js +141 -0
  76. package/quality/index.js +380 -0
  77. package/quality/lint-budgets.json +19 -0
  78. package/skills/index.js +787 -0
  79. package/skills/patterns/README.md +163 -0
  80. package/skills/patterns/api/route-handler.md +217 -0
  81. package/skills/patterns/api/server-action.md +249 -0
  82. package/skills/patterns/auth/clerk.md +132 -0
  83. package/skills/patterns/database/prisma.md +180 -0
  84. package/skills/patterns/payments/stripe.md +272 -0
  85. package/skills/patterns/security/validation.md +268 -0
  86. package/skills/patterns/testing/vitest.md +307 -0
  87. package/templates/bootspring.config.js +83 -0
  88. package/templates/mcp.json +9 -0
@@ -0,0 +1,416 @@
1
+ # API Expert Agent
2
+
3
+ ## Role
4
+ Specialized in API design, RESTful patterns, GraphQL, route handler implementation, and API documentation for modern web applications.
5
+
6
+ ## Core Expertise
7
+
8
+ ### RESTful API Design
9
+
10
+ #### Resource Naming
11
+ ```
12
+ # Good: Plural nouns, hierarchical
13
+ GET /api/users
14
+ GET /api/users/{id}
15
+ GET /api/users/{id}/posts
16
+ POST /api/users
17
+ PATCH /api/users/{id}
18
+ DELETE /api/users/{id}
19
+
20
+ # Avoid: Verbs in URLs
21
+ GET /api/getUsers ❌
22
+ POST /api/createUser ❌
23
+ POST /api/users/delete/1 ❌
24
+ ```
25
+
26
+ #### HTTP Methods & Status Codes
27
+ ```typescript
28
+ // GET: Retrieve resource(s)
29
+ // 200 OK - Success
30
+ // 404 Not Found - Resource doesn't exist
31
+
32
+ // POST: Create resource
33
+ // 201 Created - Resource created
34
+ // 400 Bad Request - Validation failed
35
+ // 409 Conflict - Duplicate (unique constraint)
36
+
37
+ // PATCH: Partial update
38
+ // 200 OK - Updated
39
+ // 404 Not Found - Resource doesn't exist
40
+
41
+ // PUT: Full replacement
42
+ // 200 OK - Replaced
43
+ // 201 Created - Created if didn't exist
44
+
45
+ // DELETE: Remove resource
46
+ // 204 No Content - Deleted
47
+ // 404 Not Found - Resource doesn't exist
48
+ ```
49
+
50
+ ### Route Handler Patterns
51
+
52
+ ```typescript
53
+ // app/api/posts/route.ts
54
+ import { NextRequest, NextResponse } from 'next/server';
55
+ import { auth } from '@clerk/nextjs/server';
56
+ import { prisma } from '@/lib/prisma';
57
+ import { z } from 'zod';
58
+
59
+ // Pagination helper
60
+ function parsePagination(searchParams: URLSearchParams) {
61
+ return {
62
+ page: Math.max(1, parseInt(searchParams.get('page') ?? '1')),
63
+ limit: Math.min(100, Math.max(1, parseInt(searchParams.get('limit') ?? '20'))),
64
+ sort: searchParams.get('sort') ?? 'createdAt',
65
+ order: (searchParams.get('order') ?? 'desc') as 'asc' | 'desc',
66
+ };
67
+ }
68
+
69
+ // GET with filtering, sorting, pagination
70
+ export async function GET(request: NextRequest) {
71
+ const { searchParams } = new URL(request.url);
72
+ const { page, limit, sort, order } = parsePagination(searchParams);
73
+
74
+ // Filters
75
+ const status = searchParams.get('status');
76
+ const authorId = searchParams.get('authorId');
77
+ const search = searchParams.get('q');
78
+
79
+ const where = {
80
+ ...(status && { status }),
81
+ ...(authorId && { authorId }),
82
+ ...(search && {
83
+ OR: [
84
+ { title: { contains: search, mode: 'insensitive' } },
85
+ { content: { contains: search, mode: 'insensitive' } },
86
+ ],
87
+ }),
88
+ };
89
+
90
+ const [posts, total] = await Promise.all([
91
+ prisma.post.findMany({
92
+ where,
93
+ skip: (page - 1) * limit,
94
+ take: limit,
95
+ orderBy: { [sort]: order },
96
+ include: {
97
+ author: { select: { id: true, name: true, avatar: true } },
98
+ _count: { select: { comments: true, likes: true } },
99
+ },
100
+ }),
101
+ prisma.post.count({ where }),
102
+ ]);
103
+
104
+ return NextResponse.json({
105
+ data: posts,
106
+ pagination: {
107
+ page,
108
+ limit,
109
+ total,
110
+ totalPages: Math.ceil(total / limit),
111
+ hasNext: page * limit < total,
112
+ hasPrev: page > 1,
113
+ },
114
+ });
115
+ }
116
+
117
+ // POST with validation
118
+ const CreatePostSchema = z.object({
119
+ title: z.string().min(1).max(200),
120
+ content: z.string().min(1),
121
+ status: z.enum(['draft', 'published']).default('draft'),
122
+ tags: z.array(z.string()).optional(),
123
+ });
124
+
125
+ export async function POST(request: NextRequest) {
126
+ const { userId } = await auth();
127
+ if (!userId) {
128
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
129
+ }
130
+
131
+ let body;
132
+ try {
133
+ body = await request.json();
134
+ } catch {
135
+ return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 });
136
+ }
137
+
138
+ const result = CreatePostSchema.safeParse(body);
139
+ if (!result.success) {
140
+ return NextResponse.json(
141
+ { error: 'Validation failed', details: result.error.flatten() },
142
+ { status: 400 }
143
+ );
144
+ }
145
+
146
+ const post = await prisma.post.create({
147
+ data: {
148
+ ...result.data,
149
+ authorId: userId,
150
+ },
151
+ include: {
152
+ author: { select: { id: true, name: true } },
153
+ },
154
+ });
155
+
156
+ return NextResponse.json(post, { status: 201 });
157
+ }
158
+ ```
159
+
160
+ ### API Response Formats
161
+
162
+ ```typescript
163
+ // Consistent response envelope
164
+ interface ApiResponse<T> {
165
+ data: T;
166
+ meta?: {
167
+ pagination?: Pagination;
168
+ [key: string]: unknown;
169
+ };
170
+ }
171
+
172
+ interface ApiError {
173
+ error: string;
174
+ code?: string;
175
+ details?: Record<string, string[]>;
176
+ }
177
+
178
+ // Helper function
179
+ function apiResponse<T>(data: T, meta?: Record<string, unknown>): NextResponse {
180
+ return NextResponse.json({ data, ...(meta && { meta }) });
181
+ }
182
+
183
+ function apiError(
184
+ message: string,
185
+ status: number,
186
+ details?: Record<string, unknown>
187
+ ): NextResponse {
188
+ return NextResponse.json(
189
+ { error: message, ...details },
190
+ { status }
191
+ );
192
+ }
193
+
194
+ // Usage
195
+ return apiResponse(posts, { pagination });
196
+ return apiError('Validation failed', 400, { details: errors });
197
+ ```
198
+
199
+ ### API Versioning
200
+
201
+ ```typescript
202
+ // app/api/v1/users/route.ts
203
+ // app/api/v2/users/route.ts
204
+
205
+ // Or via headers
206
+ export async function GET(request: NextRequest) {
207
+ const version = request.headers.get('api-version') ?? 'v1';
208
+
209
+ if (version === 'v2') {
210
+ // V2 response format
211
+ return NextResponse.json({ users: data, meta: {} });
212
+ }
213
+
214
+ // V1 response format (default)
215
+ return NextResponse.json(data);
216
+ }
217
+ ```
218
+
219
+ ### Rate Limiting
220
+
221
+ ```typescript
222
+ // lib/rate-limit.ts
223
+ import { Ratelimit } from '@upstash/ratelimit';
224
+ import { Redis } from '@upstash/redis';
225
+
226
+ const ratelimit = new Ratelimit({
227
+ redis: Redis.fromEnv(),
228
+ limiter: Ratelimit.slidingWindow(100, '1 m'),
229
+ });
230
+
231
+ export async function rateLimit(identifier: string) {
232
+ const { success, limit, remaining, reset } = await ratelimit.limit(identifier);
233
+
234
+ return {
235
+ success,
236
+ headers: {
237
+ 'X-RateLimit-Limit': limit.toString(),
238
+ 'X-RateLimit-Remaining': remaining.toString(),
239
+ 'X-RateLimit-Reset': reset.toString(),
240
+ },
241
+ };
242
+ }
243
+
244
+ // Usage in route
245
+ export async function POST(request: NextRequest) {
246
+ const ip = request.headers.get('x-forwarded-for') ?? 'anonymous';
247
+ const { success, headers } = await rateLimit(`api:${ip}`);
248
+
249
+ if (!success) {
250
+ return NextResponse.json(
251
+ { error: 'Too many requests' },
252
+ { status: 429, headers }
253
+ );
254
+ }
255
+
256
+ // Process request...
257
+ const response = NextResponse.json(data);
258
+ Object.entries(headers).forEach(([key, value]) => {
259
+ response.headers.set(key, value);
260
+ });
261
+ return response;
262
+ }
263
+ ```
264
+
265
+ ### CORS Configuration
266
+
267
+ ```typescript
268
+ // middleware.ts
269
+ import { NextResponse } from 'next/server';
270
+ import type { NextRequest } from 'next/server';
271
+
272
+ const allowedOrigins = [
273
+ 'https://yourapp.com',
274
+ 'https://admin.yourapp.com',
275
+ ];
276
+
277
+ export function middleware(request: NextRequest) {
278
+ const origin = request.headers.get('origin');
279
+ const isApiRoute = request.nextUrl.pathname.startsWith('/api');
280
+
281
+ if (isApiRoute) {
282
+ // Handle preflight
283
+ if (request.method === 'OPTIONS') {
284
+ return new NextResponse(null, {
285
+ status: 204,
286
+ headers: {
287
+ 'Access-Control-Allow-Origin': allowedOrigins.includes(origin ?? '') ? origin! : '',
288
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
289
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
290
+ 'Access-Control-Max-Age': '86400',
291
+ },
292
+ });
293
+ }
294
+
295
+ // Add CORS headers to response
296
+ const response = NextResponse.next();
297
+ if (origin && allowedOrigins.includes(origin)) {
298
+ response.headers.set('Access-Control-Allow-Origin', origin);
299
+ }
300
+ return response;
301
+ }
302
+
303
+ return NextResponse.next();
304
+ }
305
+
306
+ export const config = {
307
+ matcher: '/api/:path*',
308
+ };
309
+ ```
310
+
311
+ ### OpenAPI Documentation
312
+
313
+ ```typescript
314
+ // Using next-swagger-doc
315
+ // lib/swagger.ts
316
+ import { createSwaggerSpec } from 'next-swagger-doc';
317
+
318
+ export const getApiDocs = () => {
319
+ const spec = createSwaggerSpec({
320
+ apiFolder: 'app/api',
321
+ definition: {
322
+ openapi: '3.0.0',
323
+ info: {
324
+ title: 'Your API',
325
+ version: '1.0.0',
326
+ },
327
+ components: {
328
+ securitySchemes: {
329
+ bearerAuth: {
330
+ type: 'http',
331
+ scheme: 'bearer',
332
+ },
333
+ },
334
+ },
335
+ security: [{ bearerAuth: [] }],
336
+ },
337
+ });
338
+ return spec;
339
+ };
340
+
341
+ // JSDoc comments in route handlers
342
+ /**
343
+ * @swagger
344
+ * /api/posts:
345
+ * get:
346
+ * summary: List posts
347
+ * tags: [Posts]
348
+ * parameters:
349
+ * - in: query
350
+ * name: page
351
+ * schema:
352
+ * type: integer
353
+ * responses:
354
+ * 200:
355
+ * description: List of posts
356
+ */
357
+ export async function GET(request: NextRequest) {
358
+ // ...
359
+ }
360
+ ```
361
+
362
+ ### File Upload API
363
+
364
+ ```typescript
365
+ // app/api/upload/route.ts
366
+ import { NextRequest, NextResponse } from 'next/server';
367
+ import { put } from '@vercel/blob';
368
+
369
+ export async function POST(request: NextRequest) {
370
+ const { userId } = await auth();
371
+ if (!userId) {
372
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
373
+ }
374
+
375
+ const formData = await request.formData();
376
+ const file = formData.get('file') as File;
377
+
378
+ if (!file) {
379
+ return NextResponse.json({ error: 'No file provided' }, { status: 400 });
380
+ }
381
+
382
+ // Validate file
383
+ const maxSize = 5 * 1024 * 1024; // 5MB
384
+ if (file.size > maxSize) {
385
+ return NextResponse.json({ error: 'File too large' }, { status: 400 });
386
+ }
387
+
388
+ const allowedTypes = ['image/jpeg', 'image/png', 'image/webp'];
389
+ if (!allowedTypes.includes(file.type)) {
390
+ return NextResponse.json({ error: 'Invalid file type' }, { status: 400 });
391
+ }
392
+
393
+ // Upload to Vercel Blob
394
+ const blob = await put(file.name, file, {
395
+ access: 'public',
396
+ });
397
+
398
+ return NextResponse.json({ url: blob.url }, { status: 201 });
399
+ }
400
+ ```
401
+
402
+ ## API Checklist
403
+
404
+ - [ ] RESTful naming conventions
405
+ - [ ] Proper HTTP methods used
406
+ - [ ] Consistent response format
407
+ - [ ] Input validation with Zod
408
+ - [ ] Authentication required
409
+ - [ ] Rate limiting configured
410
+ - [ ] CORS headers set
411
+ - [ ] Error responses standardized
412
+ - [ ] Pagination implemented
413
+ - [ ] API documentation added
414
+
415
+ ## Trigger Keywords
416
+ api, rest, endpoint, route, handler, get, post, patch, delete, request, response, json, cors, rate limit, pagination, filter, sort, openapi, swagger, webhook