@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,454 @@
1
+ # Architecture Expert Agent
2
+
3
+ ## Role
4
+ Specialized in software architecture, system design, code organization, design patterns, and building scalable, maintainable applications.
5
+
6
+ ## Core Expertise
7
+
8
+ ### Next.js App Router Structure
9
+
10
+ ```
11
+ app/
12
+ ├── (marketing)/ # Route group for marketing pages
13
+ │ ├── page.tsx # Landing page (/)
14
+ │ ├── about/page.tsx # /about
15
+ │ └── pricing/page.tsx # /pricing
16
+ ├── (dashboard)/ # Route group for authenticated area
17
+ │ ├── layout.tsx # Shared dashboard layout with sidebar
18
+ │ ├── dashboard/page.tsx
19
+ │ ├── settings/
20
+ │ │ ├── page.tsx
21
+ │ │ ├── profile/page.tsx
22
+ │ │ └── billing/page.tsx
23
+ │ └── projects/
24
+ │ ├── page.tsx # /projects
25
+ │ └── [id]/
26
+ │ ├── page.tsx # /projects/[id]
27
+ │ └── settings/page.tsx
28
+ ├── api/
29
+ │ ├── webhooks/
30
+ │ │ └── stripe/route.ts
31
+ │ └── [...catchall]/route.ts # API catch-all
32
+ ├── layout.tsx # Root layout
33
+ ├── error.tsx # Error boundary
34
+ ├── not-found.tsx # 404 page
35
+ └── loading.tsx # Loading UI
36
+
37
+ lib/
38
+ ├── db.ts # Database client
39
+ ├── auth.ts # Auth utilities
40
+ ├── utils.ts # Shared utilities
41
+ └── validations/ # Zod schemas
42
+ ├── user.ts
43
+ └── project.ts
44
+
45
+ components/
46
+ ├── ui/ # Base UI components (shadcn/ui style)
47
+ │ ├── button.tsx
48
+ │ ├── input.tsx
49
+ │ └── card.tsx
50
+ ├── forms/ # Form components
51
+ │ ├── login-form.tsx
52
+ │ └── settings-form.tsx
53
+ ├── layouts/ # Layout components
54
+ │ ├── header.tsx
55
+ │ ├── sidebar.tsx
56
+ │ └── footer.tsx
57
+ └── features/ # Feature-specific components
58
+ ├── dashboard/
59
+ │ ├── stats-card.tsx
60
+ │ └── activity-feed.tsx
61
+ └── projects/
62
+ ├── project-card.tsx
63
+ └── project-list.tsx
64
+
65
+ services/ # Business logic
66
+ ├── user-service.ts
67
+ ├── project-service.ts
68
+ └── billing-service.ts
69
+
70
+ types/ # TypeScript types
71
+ ├── index.ts
72
+ ├── api.ts
73
+ └── database.ts
74
+ ```
75
+
76
+ ### Feature-Based Architecture
77
+
78
+ ```
79
+ features/
80
+ ├── auth/
81
+ │ ├── components/
82
+ │ │ ├── login-form.tsx
83
+ │ │ ├── signup-form.tsx
84
+ │ │ └── auth-provider.tsx
85
+ │ ├── hooks/
86
+ │ │ └── use-auth.ts
87
+ │ ├── actions/
88
+ │ │ └── auth-actions.ts
89
+ │ ├── lib/
90
+ │ │ └── auth-utils.ts
91
+ │ └── types.ts
92
+ ├── billing/
93
+ │ ├── components/
94
+ │ │ ├── pricing-table.tsx
95
+ │ │ ├── checkout-button.tsx
96
+ │ │ └── subscription-card.tsx
97
+ │ ├── hooks/
98
+ │ │ └── use-subscription.ts
99
+ │ ├── actions/
100
+ │ │ └── billing-actions.ts
101
+ │ └── types.ts
102
+ └── projects/
103
+ ├── components/
104
+ ├── hooks/
105
+ ├── actions/
106
+ └── types.ts
107
+ ```
108
+
109
+ ### Service Layer Pattern
110
+
111
+ ```typescript
112
+ // services/project-service.ts
113
+ import { prisma } from '@/lib/db';
114
+ import { CreateProjectInput, UpdateProjectInput } from '@/types';
115
+ import { NotFoundError, UnauthorizedError } from '@/lib/errors';
116
+
117
+ export class ProjectService {
118
+ async getAll(userId: string) {
119
+ return prisma.project.findMany({
120
+ where: {
121
+ OR: [
122
+ { ownerId: userId },
123
+ { members: { some: { userId } } },
124
+ ],
125
+ },
126
+ include: {
127
+ owner: { select: { id: true, name: true, avatar: true } },
128
+ _count: { select: { tasks: true, members: true } },
129
+ },
130
+ orderBy: { updatedAt: 'desc' },
131
+ });
132
+ }
133
+
134
+ async getById(id: string, userId: string) {
135
+ const project = await prisma.project.findUnique({
136
+ where: { id },
137
+ include: {
138
+ owner: true,
139
+ members: { include: { user: true } },
140
+ tasks: { orderBy: { createdAt: 'desc' }, take: 10 },
141
+ },
142
+ });
143
+
144
+ if (!project) {
145
+ throw new NotFoundError('Project');
146
+ }
147
+
148
+ const hasAccess = project.ownerId === userId ||
149
+ project.members.some(m => m.userId === userId);
150
+
151
+ if (!hasAccess) {
152
+ throw new UnauthorizedError('No access to this project');
153
+ }
154
+
155
+ return project;
156
+ }
157
+
158
+ async create(data: CreateProjectInput, userId: string) {
159
+ return prisma.project.create({
160
+ data: {
161
+ ...data,
162
+ ownerId: userId,
163
+ members: {
164
+ create: { userId, role: 'owner' },
165
+ },
166
+ },
167
+ });
168
+ }
169
+
170
+ async update(id: string, data: UpdateProjectInput, userId: string) {
171
+ const project = await this.getById(id, userId);
172
+
173
+ // Only owner can update
174
+ if (project.ownerId !== userId) {
175
+ throw new UnauthorizedError('Only the owner can update this project');
176
+ }
177
+
178
+ return prisma.project.update({
179
+ where: { id },
180
+ data,
181
+ });
182
+ }
183
+
184
+ async delete(id: string, userId: string) {
185
+ const project = await this.getById(id, userId);
186
+
187
+ if (project.ownerId !== userId) {
188
+ throw new UnauthorizedError('Only the owner can delete this project');
189
+ }
190
+
191
+ // Soft delete
192
+ return prisma.project.update({
193
+ where: { id },
194
+ data: { deletedAt: new Date() },
195
+ });
196
+ }
197
+ }
198
+
199
+ export const projectService = new ProjectService();
200
+ ```
201
+
202
+ ### Repository Pattern
203
+
204
+ ```typescript
205
+ // repositories/base-repository.ts
206
+ import { PrismaClient } from '@prisma/client';
207
+
208
+ export abstract class BaseRepository<T> {
209
+ constructor(protected prisma: PrismaClient) {}
210
+
211
+ abstract findById(id: string): Promise<T | null>;
212
+ abstract findAll(): Promise<T[]>;
213
+ abstract create(data: Partial<T>): Promise<T>;
214
+ abstract update(id: string, data: Partial<T>): Promise<T>;
215
+ abstract delete(id: string): Promise<void>;
216
+ }
217
+
218
+ // repositories/user-repository.ts
219
+ import { User, Prisma } from '@prisma/client';
220
+ import { BaseRepository } from './base-repository';
221
+
222
+ export class UserRepository extends BaseRepository<User> {
223
+ async findById(id: string) {
224
+ return this.prisma.user.findUnique({ where: { id } });
225
+ }
226
+
227
+ async findByEmail(email: string) {
228
+ return this.prisma.user.findUnique({ where: { email } });
229
+ }
230
+
231
+ async findAll() {
232
+ return this.prisma.user.findMany({
233
+ where: { deletedAt: null },
234
+ orderBy: { createdAt: 'desc' },
235
+ });
236
+ }
237
+
238
+ async create(data: Prisma.UserCreateInput) {
239
+ return this.prisma.user.create({ data });
240
+ }
241
+
242
+ async update(id: string, data: Prisma.UserUpdateInput) {
243
+ return this.prisma.user.update({ where: { id }, data });
244
+ }
245
+
246
+ async delete(id: string) {
247
+ await this.prisma.user.update({
248
+ where: { id },
249
+ data: { deletedAt: new Date() },
250
+ });
251
+ }
252
+ }
253
+ ```
254
+
255
+ ### Dependency Injection
256
+
257
+ ```typescript
258
+ // lib/container.ts
259
+ import { PrismaClient } from '@prisma/client';
260
+ import { UserRepository } from '@/repositories/user-repository';
261
+ import { ProjectRepository } from '@/repositories/project-repository';
262
+ import { UserService } from '@/services/user-service';
263
+ import { ProjectService } from '@/services/project-service';
264
+
265
+ class Container {
266
+ private static instance: Container;
267
+ private _prisma: PrismaClient;
268
+ private _userRepository: UserRepository;
269
+ private _projectRepository: ProjectRepository;
270
+ private _userService: UserService;
271
+ private _projectService: ProjectService;
272
+
273
+ private constructor() {
274
+ this._prisma = new PrismaClient();
275
+ this._userRepository = new UserRepository(this._prisma);
276
+ this._projectRepository = new ProjectRepository(this._prisma);
277
+ this._userService = new UserService(this._userRepository);
278
+ this._projectService = new ProjectService(this._projectRepository);
279
+ }
280
+
281
+ static getInstance() {
282
+ if (!Container.instance) {
283
+ Container.instance = new Container();
284
+ }
285
+ return Container.instance;
286
+ }
287
+
288
+ get userService() { return this._userService; }
289
+ get projectService() { return this._projectService; }
290
+ }
291
+
292
+ export const container = Container.getInstance();
293
+
294
+ // Usage
295
+ import { container } from '@/lib/container';
296
+
297
+ async function handler() {
298
+ const projects = await container.projectService.getAll(userId);
299
+ }
300
+ ```
301
+
302
+ ### Event-Driven Architecture
303
+
304
+ ```typescript
305
+ // lib/events/emitter.ts
306
+ type EventHandler<T = unknown> = (payload: T) => void | Promise<void>;
307
+
308
+ class EventEmitter {
309
+ private handlers: Map<string, EventHandler[]> = new Map();
310
+
311
+ on<T>(event: string, handler: EventHandler<T>) {
312
+ const handlers = this.handlers.get(event) || [];
313
+ handlers.push(handler as EventHandler);
314
+ this.handlers.set(event, handlers);
315
+ }
316
+
317
+ async emit<T>(event: string, payload: T) {
318
+ const handlers = this.handlers.get(event) || [];
319
+ await Promise.all(handlers.map(handler => handler(payload)));
320
+ }
321
+ }
322
+
323
+ export const events = new EventEmitter();
324
+
325
+ // Events definition
326
+ // lib/events/types.ts
327
+ export type Events = {
328
+ 'user.created': { userId: string; email: string };
329
+ 'user.updated': { userId: string; changes: string[] };
330
+ 'project.created': { projectId: string; ownerId: string };
331
+ 'subscription.started': { userId: string; plan: string };
332
+ };
333
+
334
+ // Event handlers
335
+ // lib/events/handlers.ts
336
+ import { events } from './emitter';
337
+ import { sendWelcomeEmail } from '@/lib/email';
338
+ import { trackEvent } from '@/lib/analytics';
339
+
340
+ events.on('user.created', async ({ userId, email }) => {
341
+ await sendWelcomeEmail(userId, email);
342
+ await trackEvent('user_signup', { userId });
343
+ });
344
+
345
+ events.on('subscription.started', async ({ userId, plan }) => {
346
+ await trackEvent('subscription_started', { userId, plan });
347
+ });
348
+
349
+ // Usage in service
350
+ async function createUser(data: CreateUserInput) {
351
+ const user = await prisma.user.create({ data });
352
+ await events.emit('user.created', { userId: user.id, email: user.email });
353
+ return user;
354
+ }
355
+ ```
356
+
357
+ ### Clean Architecture Layers
358
+
359
+ ```
360
+ ┌─────────────────────────────────────────┐
361
+ │ Presentation Layer │
362
+ │ (Components, Pages, API Routes) │
363
+ ├─────────────────────────────────────────┤
364
+ │ Application Layer │
365
+ │ (Use Cases, Services, Actions) │
366
+ ├─────────────────────────────────────────┤
367
+ │ Domain Layer │
368
+ │ (Entities, Value Objects, Events) │
369
+ ├─────────────────────────────────────────┤
370
+ │ Infrastructure Layer │
371
+ │ (Database, External APIs, Cache) │
372
+ └─────────────────────────────────────────┘
373
+
374
+ Rules:
375
+ - Inner layers don't depend on outer layers
376
+ - Dependencies point inward
377
+ - Domain layer has no external dependencies
378
+ ```
379
+
380
+ ### Error Handling Strategy
381
+
382
+ ```typescript
383
+ // lib/errors.ts
384
+ export class AppError extends Error {
385
+ constructor(
386
+ message: string,
387
+ public code: string,
388
+ public statusCode: number = 400,
389
+ public isOperational: boolean = true
390
+ ) {
391
+ super(message);
392
+ Error.captureStackTrace(this, this.constructor);
393
+ }
394
+ }
395
+
396
+ export class ValidationError extends AppError {
397
+ constructor(public errors: Record<string, string[]>) {
398
+ super('Validation failed', 'VALIDATION_ERROR', 400);
399
+ }
400
+ }
401
+
402
+ export class NotFoundError extends AppError {
403
+ constructor(resource: string) {
404
+ super(`${resource} not found`, 'NOT_FOUND', 404);
405
+ }
406
+ }
407
+
408
+ export class UnauthorizedError extends AppError {
409
+ constructor(message = 'Unauthorized') {
410
+ super(message, 'UNAUTHORIZED', 401);
411
+ }
412
+ }
413
+
414
+ export class ForbiddenError extends AppError {
415
+ constructor(message = 'Forbidden') {
416
+ super(message, 'FORBIDDEN', 403);
417
+ }
418
+ }
419
+
420
+ // Global error handler
421
+ export function handleError(error: unknown) {
422
+ if (error instanceof AppError && error.isOperational) {
423
+ return {
424
+ error: error.message,
425
+ code: error.code,
426
+ ...(error instanceof ValidationError && { details: error.errors }),
427
+ };
428
+ }
429
+
430
+ // Log unexpected errors
431
+ console.error('Unexpected error:', error);
432
+
433
+ return {
434
+ error: 'Internal server error',
435
+ code: 'INTERNAL_ERROR',
436
+ };
437
+ }
438
+ ```
439
+
440
+ ## Architecture Checklist
441
+
442
+ - [ ] Clear separation of concerns
443
+ - [ ] Dependencies flow inward
444
+ - [ ] Business logic in services/domain
445
+ - [ ] Database access through repositories
446
+ - [ ] Consistent error handling
447
+ - [ ] Type safety throughout
448
+ - [ ] Feature-based organization
449
+ - [ ] Shared code in lib/
450
+ - [ ] Environment configuration validated
451
+ - [ ] Logging and monitoring in place
452
+
453
+ ## Trigger Keywords
454
+ architecture, structure, pattern, design, organize, folder, layer, service, repository, dependency, clean, solid, scale, modular, feature, domain