pixelcrew 0.2.2 → 0.2.6
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 +389 -315
- package/bin/pixel-agents.js +306 -149
- package/package.json +3 -1
- package/skill/SKILL.md +185 -0
- package/skill/references/anti-ai-rubric.md +30 -0
- package/skill/references/anti-ai-slop-encyclopedia.md +181 -0
- package/skill/references/commands-reference.md +135 -0
- package/skill/references/testing-and-qa-strategy.md +25 -0
- package/skill/references/token-efficiency.md +20 -0
- package/src/adapters/adapter.interface.js +77 -0
- package/src/adapters/antigravity.js +138 -0
- package/src/adapters/claude-code.js +149 -0
- package/src/adapters/codex.js +131 -0
- package/src/adapters/cursor.js +133 -0
- package/src/adapters/generic.js +63 -0
- package/src/adapters/index.js +15 -0
- package/src/adapters/kiro.js +134 -0
- package/src/adapters/registry.js +150 -0
- package/src/backend/analyzer/complexity-analyzer.js +104 -0
- package/src/backend/analyzer/requirement-analyzer.js +213 -0
- package/src/backend/analyzer/threat-analyzer.js +122 -0
- package/src/backend/api/api-designer.js +90 -0
- package/src/backend/api/error-contract.js +132 -0
- package/src/backend/api/route-generator.js +92 -0
- package/src/backend/api/schema-generator.js +64 -0
- package/src/backend/architecture/adr-generator.js +62 -0
- package/src/backend/architecture/architecture-reasoner.js +119 -0
- package/src/backend/architecture/architecture-selector.js +57 -0
- package/src/backend/architecture/tradeoff-analyzer.js +92 -0
- package/src/backend/data/data-modeler.js +114 -0
- package/src/backend/data/index-analyzer.js +93 -0
- package/src/backend/data/query-analyzer.js +41 -0
- package/src/backend/data/schema-generator.js +92 -0
- package/src/backend/data/transaction-analyzer.js +49 -0
- package/src/backend/index.js +67 -0
- package/src/backend/observability/logging-engine.js +80 -0
- package/src/backend/observability/metrics-engine.js +31 -0
- package/src/backend/observability/tracing-engine.js +16 -0
- package/src/backend/patterns/pattern-registry.js +74 -0
- package/src/backend/patterns/pattern-selector.js +39 -0
- package/src/backend/patterns/tradeoff-engine.js +17 -0
- package/src/backend/performance/cache-analyzer.js +31 -0
- package/src/backend/performance/concurrency-analyzer.js +34 -0
- package/src/backend/performance/performance-engine.js +98 -0
- package/src/backend/performance/query-optimizer.js +16 -0
- package/src/backend/reliability/failure-analyzer.js +22 -0
- package/src/backend/reliability/idempotency-engine.js +56 -0
- package/src/backend/reliability/resilience-engine.js +141 -0
- package/src/backend/reliability/retry-analyzer.js +15 -0
- package/src/backend/security/auth-selector.js +33 -0
- package/src/backend/security/authorization-engine.js +90 -0
- package/src/backend/security/policy-engine.js +49 -0
- package/src/backend/security/secret-analyzer.js +39 -0
- package/src/backend/security/security-engine.js +122 -0
- package/src/backend/security/threat-model.js +59 -0
- package/src/backend/synthesis/backend-synthesizer.js +98 -0
- package/src/backend/synthesis/infrastructure-synthesizer.js +108 -0
- package/src/backend/synthesis/module-synthesizer.js +262 -0
- package/src/backend/validation/architecture-validator.js +70 -0
- package/src/backend/validation/backend-quality-validator.js +71 -0
- package/src/backend/validation/dependency-validator.js +20 -0
- package/src/backend/validation/performance-validator.js +38 -0
- package/src/backend/validation/security-validator.js +73 -0
- package/src/commands/adapt.js +105 -0
- package/src/commands/add.js +78 -0
- package/src/commands/animate.js +48 -0
- package/src/commands/assemble.js +57 -0
- package/src/commands/audit.js +93 -0
- package/src/commands/backend.js +125 -0
- package/src/commands/bento.js +25 -0
- package/src/commands/blueprint.js +65 -0
- package/src/commands/bolder.js +48 -0
- package/src/commands/boss-fight.js +60 -0
- package/src/commands/build.js +39 -0
- package/src/commands/calibrate.js +25 -0
- package/src/commands/chromatic.js +25 -0
- package/src/commands/clarify.js +52 -0
- package/src/commands/colorize.js +57 -0
- package/src/commands/command.interface.js +28 -0
- package/src/commands/commands.js +84 -0
- package/src/commands/craft.js +57 -0
- package/src/commands/crew.js +66 -0
- package/src/commands/critique.js +25 -0
- package/src/commands/de-slop.js +25 -0
- package/src/commands/delight.js +46 -0
- package/src/commands/deploy.js +42 -0
- package/src/commands/distill.js +48 -0
- package/src/commands/doctor.js +89 -0
- package/src/commands/document.js +83 -0
- package/src/commands/eight-bit.js +25 -0
- package/src/commands/extract.js +75 -0
- package/src/commands/fix.js +46 -0
- package/src/commands/harden.js +85 -0
- package/src/commands/index.js +67 -0
- package/src/commands/install.js +75 -0
- package/src/commands/layout.js +48 -0
- package/src/commands/live.js +44 -0
- package/src/commands/manifest.js +25 -0
- package/src/commands/office.js +25 -0
- package/src/commands/onboard.js +46 -0
- package/src/commands/oneshot.js +60 -0
- package/src/commands/optimize.js +46 -0
- package/src/commands/overdrive.js +46 -0
- package/src/commands/parser.js +143 -0
- package/src/commands/pixelcrew.js +96 -0
- package/src/commands/plan.js +66 -0
- package/src/commands/polish.js +45 -0
- package/src/commands/quieter.js +48 -0
- package/src/commands/recap.js +358 -0
- package/src/commands/registry.js +353 -0
- package/src/commands/render.js +26 -0
- package/src/commands/retrofit.js +25 -0
- package/src/commands/review.js +118 -0
- package/src/commands/roster.js +25 -0
- package/src/commands/sentinel.js +25 -0
- package/src/commands/shape.js +66 -0
- package/src/commands/skills.js +57 -0
- package/src/commands/status.js +48 -0
- package/src/commands/stop.js +50 -0
- package/src/commands/sync.js +58 -0
- package/src/commands/typeset.js +58 -0
- package/src/commands/warp.js +25 -0
- package/src/core/agent-runtime.js +94 -0
- package/src/core/event-bus.js +98 -0
- package/src/core/index.js +9 -0
- package/src/core/orchestrator.js +234 -0
- package/src/core/scheduler.js +124 -0
- package/src/core/task-graph.js +185 -0
- package/src/dashboard/app.js +1172 -30
- package/src/dashboard/index.html +223 -23
- package/src/dashboard/styles.css +870 -0
- package/src/index.js +16 -0
- package/src/orchestrator/artifact-graph.js +104 -0
- package/src/orchestrator/ast-normalizer.js +147 -0
- package/src/orchestrator/code-generator.js +846 -0
- package/src/orchestrator/design-engine.js +203 -0
- package/src/orchestrator/engine.js +318 -39
- package/src/orchestrator/oneshot.js +351 -1561
- package/src/orchestrator/ontology.js +394 -0
- package/src/orchestrator/planner.js +302 -0
- package/src/orchestrator/repair-planner.js +67 -0
- package/src/orchestrator/requirement-contract.js +177 -0
- package/src/orchestrator/requirement-validator.js +39 -0
- package/src/orchestrator/semantic-engine.js +582 -0
- package/src/orchestrator/semantic-reviewer.js +179 -0
- package/src/orchestrator/skills-registry.js +194 -0
- package/src/orchestrator/task-planner.js +111 -0
- package/src/orchestrator/task-queue.js +128 -0
- package/src/orchestrator/telemetry.js +209 -0
- package/src/orchestrator/ui-synthesizer.js +245 -0
- package/src/orchestrator/visual-critic.js +106 -0
- package/src/policies/architecture/layering.policy.js +14 -0
- package/src/policies/performance/indexing.policy.js +13 -0
- package/src/policies/reliability/resilience.policy.js +13 -0
- package/src/policies/security/auth.policy.js +31 -0
- package/src/protocol/agent.js +124 -0
- package/src/protocol/event.js +78 -0
- package/src/protocol/index.js +8 -0
- package/src/protocol/skill.js +54 -0
- package/src/protocol/task.js +100 -0
- package/src/scaffold/claude-generator.js +60 -0
- package/src/scaffold/commands-catalog.js +321 -0
- package/src/scaffold/cursor-generator.js +74 -0
- package/src/scaffold/ide-rules.js +133 -0
- package/src/scaffold/init.js +415 -91
- package/src/scaffold/installer.js +571 -0
- package/src/scaffold/kiro-generator.js +86 -0
- package/src/scaffold/skills-bundle.js +520 -0
- package/src/scaffold/templates.js +57 -4
- package/src/scaffold/workstations.js +364 -0
- package/src/server/server.js +292 -42
- package/src/utils/fs-safe.js +168 -0
- package/src/utils/markdown-report.js +175 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — Threat Model Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Conducts automated, lightweight STRIDE threat modeling on application requirements
|
|
5
|
+
* to derive required security controls, boundaries, and validation guards.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class ThreatAnalyzer {
|
|
9
|
+
/**
|
|
10
|
+
* Derive threat vectors and security controls from requirements
|
|
11
|
+
* @param {object} requirements - SystemRequirementsModel
|
|
12
|
+
* @param {object} ast - Semantic Project AST
|
|
13
|
+
* @returns {object} ThreatModel
|
|
14
|
+
*/
|
|
15
|
+
static analyze(requirements = {}, ast = {}) {
|
|
16
|
+
const threats = [];
|
|
17
|
+
const controls = [];
|
|
18
|
+
const boundaries = [];
|
|
19
|
+
|
|
20
|
+
const users = requirements.users || {};
|
|
21
|
+
const data = requirements.data || {};
|
|
22
|
+
const security = requirements.security || {};
|
|
23
|
+
const api = requirements.api || {};
|
|
24
|
+
|
|
25
|
+
// 1. Boundary: External Client -> API Layer
|
|
26
|
+
boundaries.push({
|
|
27
|
+
name: 'Internet to API Gateway',
|
|
28
|
+
trustLevel: 'untrusted-to-trusted',
|
|
29
|
+
controls: ['HTTPS/TLS', 'Strict Rate Limiting', 'Zod Schema Validation', 'CORS Policy', 'Security Headers']
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// 2. Authentication & Credential Theft Threats
|
|
33
|
+
if (users.authentication) {
|
|
34
|
+
threats.push({
|
|
35
|
+
id: 'THR-AUTH-001',
|
|
36
|
+
asset: 'User Credentials & Session',
|
|
37
|
+
category: 'Spoofing',
|
|
38
|
+
threat: 'Credential theft, brute-force login attacks, or session hijacking',
|
|
39
|
+
severity: 'High',
|
|
40
|
+
mitigation: 'Argon2id password hashing, HTTP-only secure SameSite cookies, progressive delay brute-force limiter'
|
|
41
|
+
});
|
|
42
|
+
controls.push('session-cookie-hardening', 'auth-rate-limiting', 'password-hashing');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 3. Multi-Tenant Cross-Tenant Access Threats
|
|
46
|
+
if (security.tenantIsolation) {
|
|
47
|
+
boundaries.push({
|
|
48
|
+
name: 'Tenant Isolation Boundary',
|
|
49
|
+
trustLevel: 'tenant-scoped',
|
|
50
|
+
controls: ['Organization Context Middleware', 'Database WHERE organization_id filter', 'Policy Guard']
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
threats.push({
|
|
54
|
+
id: 'THR-TENANT-001',
|
|
55
|
+
asset: 'Tenant Data Isolation',
|
|
56
|
+
category: 'Elevation of Privilege / Information Disclosure',
|
|
57
|
+
threat: 'Cross-tenant IDOR (Insecure Direct Object Reference) access',
|
|
58
|
+
severity: 'Critical',
|
|
59
|
+
mitigation: 'Mandatory tenant context derived strictly from authenticated session; query-level organizationId scoping'
|
|
60
|
+
});
|
|
61
|
+
controls.push('tenant-context-extractor', 'query-tenant-scoper', 'tenant-policy-guard');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 4. Data Tampering & Injection Threats
|
|
65
|
+
threats.push({
|
|
66
|
+
id: 'THR-DATA-001',
|
|
67
|
+
asset: 'Relational Database State',
|
|
68
|
+
category: 'Tampering / Injection',
|
|
69
|
+
threat: 'SQL Injection or unvalidated payload pollution',
|
|
70
|
+
severity: 'Critical',
|
|
71
|
+
mitigation: 'ORM parameterized queries (Prisma), strict Zod input schemas with unknown key stripping'
|
|
72
|
+
});
|
|
73
|
+
controls.push('parameterized-queries', 'strict-input-validation');
|
|
74
|
+
|
|
75
|
+
// 5. Transaction Race Conditions / Financial Double-Spend
|
|
76
|
+
if (data.transactions) {
|
|
77
|
+
threats.push({
|
|
78
|
+
id: 'THR-RACE-001',
|
|
79
|
+
asset: 'Financial / Inventory State',
|
|
80
|
+
category: 'Tampering',
|
|
81
|
+
threat: 'Concurrent race conditions causing double-spend or duplicate execution',
|
|
82
|
+
severity: 'High',
|
|
83
|
+
mitigation: 'ACID database transactions ($transaction), Idempotency-Key header validation, optimistic locking'
|
|
84
|
+
});
|
|
85
|
+
controls.push('idempotency-middleware', 'atomic-transactions', 'optimistic-locking');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 6. Denial of Service / Resource Exhaustion
|
|
89
|
+
if (api.rateLimiting) {
|
|
90
|
+
threats.push({
|
|
91
|
+
id: 'THR-DOS-001',
|
|
92
|
+
asset: 'API Availability',
|
|
93
|
+
category: 'Denial of Service',
|
|
94
|
+
threat: 'API endpoint flooding and resource exhaustion',
|
|
95
|
+
severity: 'Medium',
|
|
96
|
+
mitigation: 'Token Bucket / Sliding Window rate limiting per IP / User / Tenant'
|
|
97
|
+
});
|
|
98
|
+
controls.push('rate-limiter');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 7. Audit Log Tampering
|
|
102
|
+
if (security.auditLogging) {
|
|
103
|
+
threats.push({
|
|
104
|
+
id: 'THR-AUDIT-001',
|
|
105
|
+
asset: 'Compliance & Audit Trail',
|
|
106
|
+
category: 'Repudiation',
|
|
107
|
+
threat: 'Undetected administrative modifications or unauthorized data access',
|
|
108
|
+
severity: 'Medium',
|
|
109
|
+
mitigation: 'Append-only structured audit logs with actorId, IP, timestamp, and target entity metadata'
|
|
110
|
+
});
|
|
111
|
+
controls.push('audit-logger');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
boundaries,
|
|
116
|
+
threats,
|
|
117
|
+
controls: Array.from(new Set(controls)),
|
|
118
|
+
threatScore: threats.filter(t => t.severity === 'Critical').length * 25 + threats.filter(t => t.severity === 'High').length * 15,
|
|
119
|
+
complianceStandard: security.sensitiveData ? 'SOC2 / HIPAA aligned' : 'Standard Web Security'
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — API Designer Engine
|
|
3
|
+
*
|
|
4
|
+
* Designs capability-driven REST/RPC API contracts with pagination (cursor vs offset),
|
|
5
|
+
* filtering, sorting, authentication, and HTTP status codes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class APIDesigner {
|
|
9
|
+
/**
|
|
10
|
+
* Design API endpoints for entities and workflows
|
|
11
|
+
* @param {Array<object>} entities
|
|
12
|
+
* @param {Array<object>} workflows
|
|
13
|
+
* @param {object} architecture
|
|
14
|
+
* @returns {Array<object>} API Endpoints Specification
|
|
15
|
+
*/
|
|
16
|
+
static designEndpoints(entities = [], workflows = [], architecture = {}) {
|
|
17
|
+
const endpoints = [];
|
|
18
|
+
const isMultiTenant = Boolean(architecture.database?.tenantIsolation);
|
|
19
|
+
const pagination = architecture.performance?.paginationStrategy || 'cursor';
|
|
20
|
+
|
|
21
|
+
entities.forEach(ent => {
|
|
22
|
+
const slug = ent.plural ? ent.plural.toLowerCase() : `${ent.name.toLowerCase()}s`;
|
|
23
|
+
const basePath = `/api/v1/${slug}`;
|
|
24
|
+
|
|
25
|
+
// 1. List / Search Collection
|
|
26
|
+
endpoints.push({
|
|
27
|
+
id: `api-list-${slug}`,
|
|
28
|
+
name: `List ${ent.title || ent.name}`,
|
|
29
|
+
method: 'GET',
|
|
30
|
+
path: basePath,
|
|
31
|
+
entity: ent.name,
|
|
32
|
+
type: 'collection',
|
|
33
|
+
pagination,
|
|
34
|
+
authRequired: architecture.authentication?.required ?? false,
|
|
35
|
+
summary: `Retrieve paginated list of ${ent.plural || ent.name} with filtering and sorting`
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// 2. Get by ID
|
|
39
|
+
endpoints.push({
|
|
40
|
+
id: `api-get-${slug}-id`,
|
|
41
|
+
name: `Get ${ent.name} by ID`,
|
|
42
|
+
method: 'GET',
|
|
43
|
+
path: `${basePath}/:id`,
|
|
44
|
+
entity: ent.name,
|
|
45
|
+
type: 'item',
|
|
46
|
+
authRequired: architecture.authentication?.required ?? false,
|
|
47
|
+
summary: `Retrieve a single ${ent.name} record by unique identifier`
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// 3. Create Entity
|
|
51
|
+
endpoints.push({
|
|
52
|
+
id: `api-create-${slug}`,
|
|
53
|
+
name: `Create ${ent.name}`,
|
|
54
|
+
method: 'POST',
|
|
55
|
+
path: basePath,
|
|
56
|
+
entity: ent.name,
|
|
57
|
+
type: 'mutation',
|
|
58
|
+
authRequired: architecture.authentication?.required ?? false,
|
|
59
|
+
requiresIdempotency: architecture.database?.transactions ?? false,
|
|
60
|
+
summary: `Create a new ${ent.name} record`
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// 4. Update Entity
|
|
64
|
+
endpoints.push({
|
|
65
|
+
id: `api-update-${slug}-id`,
|
|
66
|
+
name: `Update ${ent.name}`,
|
|
67
|
+
method: 'PATCH',
|
|
68
|
+
path: `${basePath}/:id`,
|
|
69
|
+
entity: ent.name,
|
|
70
|
+
type: 'mutation',
|
|
71
|
+
authRequired: architecture.authentication?.required ?? false,
|
|
72
|
+
summary: `Update existing ${ent.name} fields`
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// 5. Delete Entity
|
|
76
|
+
endpoints.push({
|
|
77
|
+
id: `api-delete-${slug}-id`,
|
|
78
|
+
name: `Delete ${ent.name}`,
|
|
79
|
+
method: 'DELETE',
|
|
80
|
+
path: `${basePath}/:id`,
|
|
81
|
+
entity: ent.name,
|
|
82
|
+
type: 'mutation',
|
|
83
|
+
authRequired: architecture.authentication?.required ?? false,
|
|
84
|
+
summary: `Delete ${ent.name} record`
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return endpoints;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — RFC 7807 Problem Details Error Contract
|
|
3
|
+
*
|
|
4
|
+
* Standardized HTTP problem details for APIs (RFC 7807).
|
|
5
|
+
* Prevents leaking stack traces, database credentials, or internal file paths in production.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class ErrorContract {
|
|
9
|
+
/**
|
|
10
|
+
* Synthesize TypeScript RFC 7807 Error Classes & Middleware
|
|
11
|
+
* @returns {string} TypeScript Error Contract source
|
|
12
|
+
*/
|
|
13
|
+
static generateErrorClasses() {
|
|
14
|
+
return `/**
|
|
15
|
+
* RFC 7807 Problem Details Standard Error System
|
|
16
|
+
* Auto-generated by Pixel Crew Backend Synthesizer
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export interface ProblemDetails {
|
|
20
|
+
type: string;
|
|
21
|
+
title: string;
|
|
22
|
+
status: number;
|
|
23
|
+
detail: string;
|
|
24
|
+
instance?: string;
|
|
25
|
+
invalidParams?: Array<{ name: string; reason: string }>;
|
|
26
|
+
timestamp: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class AppError extends Error {
|
|
30
|
+
public readonly status: number;
|
|
31
|
+
public readonly type: string;
|
|
32
|
+
public readonly title: string;
|
|
33
|
+
public readonly detail: string;
|
|
34
|
+
public readonly invalidParams?: Array<{ name: string; reason: string }>;
|
|
35
|
+
|
|
36
|
+
constructor(status: number, title: string, detail: string, type: string = "about:blank", invalidParams?: Array<{ name: string; reason: string }>) {
|
|
37
|
+
super(detail);
|
|
38
|
+
this.name = this.constructor.name;
|
|
39
|
+
this.status = status;
|
|
40
|
+
this.title = title;
|
|
41
|
+
this.detail = detail;
|
|
42
|
+
this.type = type;
|
|
43
|
+
this.invalidParams = invalidParams;
|
|
44
|
+
Error.captureStackTrace(this, this.constructor);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public toProblemDetails(instance?: string): ProblemDetails {
|
|
48
|
+
return {
|
|
49
|
+
type: this.type,
|
|
50
|
+
title: this.title,
|
|
51
|
+
status: this.status,
|
|
52
|
+
detail: this.detail,
|
|
53
|
+
instance,
|
|
54
|
+
invalidParams: this.invalidParams,
|
|
55
|
+
timestamp: new Date().toISOString()
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export class ValidationError extends AppError {
|
|
61
|
+
constructor(detail: string = "Invalid request payload", invalidParams?: Array<{ name: string; reason: string }>) {
|
|
62
|
+
super(422, "Unprocessable Entity", detail, "https://api.pixelcrew.dev/errors/validation-error", invalidParams);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export class AuthenticationError extends AppError {
|
|
67
|
+
constructor(detail: string = "Authentication is required to access this resource") {
|
|
68
|
+
super(401, "Unauthorized", detail, "https://api.pixelcrew.dev/errors/authentication-error");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export class ForbiddenError extends AppError {
|
|
73
|
+
constructor(detail: string = "You do not have permission to perform this action") {
|
|
74
|
+
super(403, "Forbidden", detail, "https://api.pixelcrew.dev/errors/forbidden-error");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export class NotFoundError extends AppError {
|
|
79
|
+
constructor(resource: string = "Resource", id?: string) {
|
|
80
|
+
const detail = id ? \`\${resource} with ID '\${id}' was not found\` : \`\${resource} was not found\`;
|
|
81
|
+
super(404, "Not Found", detail, "https://api.pixelcrew.dev/errors/not-found");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class ConflictError extends AppError {
|
|
86
|
+
constructor(detail: string = "Resource already exists or conflicting state detected") {
|
|
87
|
+
super(409, "Conflict", detail, "https://api.pixelcrew.dev/errors/conflict");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export class RateLimitError extends AppError {
|
|
92
|
+
constructor(retryAfterSeconds: number = 60) {
|
|
93
|
+
super(429, "Too Many Requests", \`Rate limit exceeded. Please retry in \${retryAfterSeconds}s\`, "https://api.pixelcrew.dev/errors/rate-limit");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export class InternalServerError extends AppError {
|
|
98
|
+
constructor(detail: string = "An unexpected error occurred while processing your request") {
|
|
99
|
+
super(500, "Internal Server Error", detail, "https://api.pixelcrew.dev/errors/internal-server-error");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Global API Error Response Formatter
|
|
105
|
+
*/
|
|
106
|
+
export function formatErrorResponse(error: unknown, instancePath?: string): { status: number; body: ProblemDetails } {
|
|
107
|
+
if (error instanceof AppError) {
|
|
108
|
+
return {
|
|
109
|
+
status: error.status,
|
|
110
|
+
body: error.toProblemDetails(instancePath)
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Hide internal exception details in production
|
|
115
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
116
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
status: 500,
|
|
120
|
+
body: {
|
|
121
|
+
type: "https://api.pixelcrew.dev/errors/internal-server-error",
|
|
122
|
+
title: "Internal Server Error",
|
|
123
|
+
status: 500,
|
|
124
|
+
detail: isDev ? message : "An internal server error occurred",
|
|
125
|
+
instance: instancePath,
|
|
126
|
+
timestamp: new Date().toISOString()
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
`;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — Route Handler Generator
|
|
3
|
+
*
|
|
4
|
+
* Synthesizes Next.js App Router API Route handlers (route.ts) that delegate cleanly
|
|
5
|
+
* to controllers/services, avoiding inline database logic or unvalidated inputs.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class RouteGenerator {
|
|
9
|
+
/**
|
|
10
|
+
* Generate Next.js App Router route.ts file for an entity collection
|
|
11
|
+
* @param {object} entity
|
|
12
|
+
* @returns {string} Route handler code
|
|
13
|
+
*/
|
|
14
|
+
static generateCollectionRoute(entity) {
|
|
15
|
+
const name = entity.name;
|
|
16
|
+
const lowerName = name.toLowerCase();
|
|
17
|
+
|
|
18
|
+
return `import { NextRequest, NextResponse } from "next/server";
|
|
19
|
+
import { ${name}Controller } from "@/modules/${lowerName}/${lowerName}.controller";
|
|
20
|
+
import { formatErrorResponse } from "@/shared/errors";
|
|
21
|
+
|
|
22
|
+
const controller = new ${name}Controller();
|
|
23
|
+
|
|
24
|
+
export async function GET(request: NextRequest) {
|
|
25
|
+
try {
|
|
26
|
+
const result = await controller.list(request);
|
|
27
|
+
return NextResponse.json(result, { status: 200 });
|
|
28
|
+
} catch (error) {
|
|
29
|
+
const { status, body } = formatErrorResponse(error, request.nextUrl.pathname);
|
|
30
|
+
return NextResponse.json(body, { status });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function POST(request: NextRequest) {
|
|
35
|
+
try {
|
|
36
|
+
const result = await controller.create(request);
|
|
37
|
+
return NextResponse.json(result, { status: 201 });
|
|
38
|
+
} catch (error) {
|
|
39
|
+
const { status, body } = formatErrorResponse(error, request.nextUrl.pathname);
|
|
40
|
+
return NextResponse.json(body, { status });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Generate Next.js App Router route.ts file for an individual entity item [id]
|
|
48
|
+
* @param {object} entity
|
|
49
|
+
* @returns {string} Route handler code
|
|
50
|
+
*/
|
|
51
|
+
static generateItemRoute(entity) {
|
|
52
|
+
const name = entity.name;
|
|
53
|
+
const lowerName = name.toLowerCase();
|
|
54
|
+
|
|
55
|
+
return `import { NextRequest, NextResponse } from "next/server";
|
|
56
|
+
import { ${name}Controller } from "@/modules/${lowerName}/${lowerName}.controller";
|
|
57
|
+
import { formatErrorResponse } from "@/shared/errors";
|
|
58
|
+
|
|
59
|
+
const controller = new ${name}Controller();
|
|
60
|
+
|
|
61
|
+
export async function GET(request: NextRequest, { params }: { params: { id: string } }) {
|
|
62
|
+
try {
|
|
63
|
+
const result = await controller.getById(params.id, request);
|
|
64
|
+
return NextResponse.json(result, { status: 200 });
|
|
65
|
+
} catch (error) {
|
|
66
|
+
const { status, body } = formatErrorResponse(error, request.nextUrl.pathname);
|
|
67
|
+
return NextResponse.json(body, { status });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function PATCH(request: NextRequest, { params }: { params: { id: string } }) {
|
|
72
|
+
try {
|
|
73
|
+
const result = await controller.update(params.id, request);
|
|
74
|
+
return NextResponse.json(result, { status: 200 });
|
|
75
|
+
} catch (error) {
|
|
76
|
+
const { status, body } = formatErrorResponse(error, request.nextUrl.pathname);
|
|
77
|
+
return NextResponse.json(body, { status });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function DELETE(request: NextRequest, { params }: { params: { id: string } }) {
|
|
82
|
+
try {
|
|
83
|
+
await controller.delete(params.id, request);
|
|
84
|
+
return new NextResponse(null, { status: 204 });
|
|
85
|
+
} catch (error) {
|
|
86
|
+
const { status, body } = formatErrorResponse(error, request.nextUrl.pathname);
|
|
87
|
+
return NextResponse.json(body, { status });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — Zod Input/Output Schema Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates runtime Zod validation schemas for request bodies, query parameters,
|
|
5
|
+
* and response models. Enforces strict input stripping and type safety.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class SchemaGenerator {
|
|
9
|
+
/**
|
|
10
|
+
* Generate Zod schemas for an entity
|
|
11
|
+
* @param {object} entity
|
|
12
|
+
* @returns {string} TypeScript Zod schema file content
|
|
13
|
+
*/
|
|
14
|
+
static generateZodSchema(entity) {
|
|
15
|
+
const name = entity.name;
|
|
16
|
+
const fields = entity.fields || [];
|
|
17
|
+
|
|
18
|
+
let code = `import { z } from "zod";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Domain Schema for ${name}
|
|
22
|
+
* Auto-generated by Pixel Crew Backend Synthesizer
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export const ${name}Schema = z.object({\n`;
|
|
26
|
+
|
|
27
|
+
fields.forEach(f => {
|
|
28
|
+
let zodType = 'z.string()';
|
|
29
|
+
if (f.type === 'number') zodType = 'z.number()';
|
|
30
|
+
else if (f.type === 'boolean') zodType = 'z.boolean()';
|
|
31
|
+
else if (f.type === 'datetime') zodType = 'z.string().datetime()';
|
|
32
|
+
else if (f.type === 'json') zodType = 'z.record(z.any())';
|
|
33
|
+
|
|
34
|
+
if (!f.required) {
|
|
35
|
+
zodType += '.optional()';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
code += ` ${f.name}: ${zodType},\n`;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
code += `});
|
|
42
|
+
|
|
43
|
+
export const Create${name}Schema = ${name}Schema.omit({\n id: true,\n createdAt: true,\n updatedAt: true\n});
|
|
44
|
+
|
|
45
|
+
export const Update${name}Schema = Create${name}Schema.partial();
|
|
46
|
+
|
|
47
|
+
export const ${name}QuerySchema = z.object({
|
|
48
|
+
page: z.coerce.number().min(1).default(1),
|
|
49
|
+
limit: z.coerce.number().min(1).max(100).default(20),
|
|
50
|
+
cursor: z.string().optional(),
|
|
51
|
+
search: z.string().optional(),
|
|
52
|
+
sortBy: z.string().default("createdAt"),
|
|
53
|
+
sortOrder: z.enum(["asc", "desc"]).default("desc")
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export type ${name}DTO = z.infer<typeof ${name}Schema>;
|
|
57
|
+
export type Create${name}DTO = z.infer<typeof Create${name}Schema>;
|
|
58
|
+
export type Update${name}DTO = z.infer<typeof Update${name}Schema>;
|
|
59
|
+
export type ${name}QueryDTO = z.infer<typeof ${name}QuerySchema>;
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
return code;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — Architecture Decision Record (ADR) Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates standard Markdown Architecture Decision Records (docs/architecture/ADR-*.md)
|
|
5
|
+
* making generated systems explainable, transparent, and maintainable by humans.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { TradeoffAnalyzer } from './tradeoff-analyzer.js';
|
|
9
|
+
|
|
10
|
+
export class ADRGenerator {
|
|
11
|
+
/**
|
|
12
|
+
* Generate complete set of ADR Markdown files
|
|
13
|
+
* @param {object} spec - ArchitectureSpecification
|
|
14
|
+
* @returns {object} Map of filename -> Markdown content
|
|
15
|
+
*/
|
|
16
|
+
static generateADRs(spec = {}) {
|
|
17
|
+
const tradeoffs = TradeoffAnalyzer.analyzeTradeoffs(spec);
|
|
18
|
+
const files = {};
|
|
19
|
+
const dateStr = new Date().toISOString().split('T')[0];
|
|
20
|
+
|
|
21
|
+
tradeoffs.forEach((t, index) => {
|
|
22
|
+
const num = String(index + 1).padStart(3, '0');
|
|
23
|
+
const slug = t.decision.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '').slice(0, 40);
|
|
24
|
+
const filename = `docs/architecture/ADR-${num}-${slug}.md`;
|
|
25
|
+
|
|
26
|
+
const md = `# ADR-${num}: ${t.decision}
|
|
27
|
+
|
|
28
|
+
**Status:** Accepted
|
|
29
|
+
**Date:** ${dateStr}
|
|
30
|
+
**Context / Reason:** ${t.reason}
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 1. Decision
|
|
35
|
+
|
|
36
|
+
We will adopt:
|
|
37
|
+
> **${t.decision}**
|
|
38
|
+
|
|
39
|
+
## 2. Benefits & Positives
|
|
40
|
+
|
|
41
|
+
${t.benefits.map(b => `- **Positive**: ${b}`).join('\n')}
|
|
42
|
+
|
|
43
|
+
## 3. Costs & Overhead
|
|
44
|
+
|
|
45
|
+
${t.costs.map(c => `- **Tradeoff**: ${c}`).join('\n')}
|
|
46
|
+
|
|
47
|
+
## 4. Alternatives Considered
|
|
48
|
+
|
|
49
|
+
${t.alternatives.map(a => `- ${a}`).join('\n')}
|
|
50
|
+
|
|
51
|
+
## 5. Risk & Mitigation Strategy
|
|
52
|
+
|
|
53
|
+
- **Identified Risk:** ${t.risk}
|
|
54
|
+
- **Mitigation:** ${t.mitigation}
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
files[filename] = md;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return files;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — Backend Architecture Reasoner
|
|
3
|
+
*
|
|
4
|
+
* Synthesizes a comprehensive ArchitectureSpecification from requirements and complexity analysis.
|
|
5
|
+
* Adheres strictly to the principle of "Minimum necessary complexity + Maximum necessary reliability".
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { RequirementAnalyzer } from '../analyzer/requirement-analyzer.js';
|
|
9
|
+
import { ComplexityAnalyzer } from '../analyzer/complexity-analyzer.js';
|
|
10
|
+
import { ThreatAnalyzer } from '../analyzer/threat-analyzer.js';
|
|
11
|
+
|
|
12
|
+
export class ArchitectureReasoner {
|
|
13
|
+
/**
|
|
14
|
+
* Derive an architecture specification from prompt & AST
|
|
15
|
+
* @param {string} prompt
|
|
16
|
+
* @param {object} ast
|
|
17
|
+
* @returns {object} ArchitectureSpecification
|
|
18
|
+
*/
|
|
19
|
+
static reason(prompt = '', ast = {}) {
|
|
20
|
+
const requirements = RequirementAnalyzer.analyze(prompt, ast);
|
|
21
|
+
const complexity = ComplexityAnalyzer.analyze(requirements, ast);
|
|
22
|
+
const threatModel = ThreatAnalyzer.analyze(requirements, ast);
|
|
23
|
+
|
|
24
|
+
// 1. Architecture Topology Selection
|
|
25
|
+
let style = 'modular-monolith';
|
|
26
|
+
if (complexity.tier === 'high') {
|
|
27
|
+
style = 'distributed-modular-services';
|
|
28
|
+
} else if (requirements.backgroundJobs.required || complexity.tier === 'medium') {
|
|
29
|
+
style = 'modular-monolith-with-workers';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 2. Database Selection
|
|
33
|
+
const dbType = requirements.application.expectedScale === 'high' || requirements.security.tenantIsolation
|
|
34
|
+
? 'postgresql'
|
|
35
|
+
: 'postgresql'; // default to postgresql with sqlite dev fallback
|
|
36
|
+
|
|
37
|
+
// 3. Cache Selection
|
|
38
|
+
const cacheRequired = requirements.performance.caching;
|
|
39
|
+
const cacheTech = (complexity.tier === 'high' || requirements.backgroundJobs.required) ? 'redis' : 'in-memory-lru';
|
|
40
|
+
|
|
41
|
+
// 4. Queue Selection
|
|
42
|
+
const queueRequired = requirements.backgroundJobs.required;
|
|
43
|
+
const queueTech = queueRequired ? (cacheTech === 'redis' ? 'bullmq' : 'in-memory-async-queue') : 'none';
|
|
44
|
+
|
|
45
|
+
// 5. Auth Strategy
|
|
46
|
+
const authStrategy = requirements.users.authentication ? 'session-cookie' : 'none';
|
|
47
|
+
const authRoles = requirements.users.roles ? 'rbac' : 'none';
|
|
48
|
+
|
|
49
|
+
// 6. Observability
|
|
50
|
+
const logging = true;
|
|
51
|
+
const metrics = complexity.tier !== 'low';
|
|
52
|
+
const tracing = complexity.tier === 'high';
|
|
53
|
+
|
|
54
|
+
const architectureSpec = {
|
|
55
|
+
style,
|
|
56
|
+
tier: complexity.tier,
|
|
57
|
+
complexityScore: complexity.totalScore,
|
|
58
|
+
|
|
59
|
+
api: {
|
|
60
|
+
style: 'rest',
|
|
61
|
+
versioning: true,
|
|
62
|
+
routeStructure: 'app-router-modular',
|
|
63
|
+
errorHandling: 'rfc-7807',
|
|
64
|
+
validation: 'zod'
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
database: {
|
|
68
|
+
type: dbType,
|
|
69
|
+
orm: 'prisma',
|
|
70
|
+
transactions: requirements.data.transactions,
|
|
71
|
+
softDelete: requirements.data.softDelete,
|
|
72
|
+
auditLog: requirements.data.auditLog,
|
|
73
|
+
tenantIsolation: requirements.security.tenantIsolation
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
cache: {
|
|
77
|
+
required: cacheRequired,
|
|
78
|
+
technology: cacheTech,
|
|
79
|
+
ttlSeconds: 300
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
queue: {
|
|
83
|
+
required: queueRequired,
|
|
84
|
+
technology: queueTech,
|
|
85
|
+
tasks: requirements.backgroundJobs.tasks
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
authentication: {
|
|
89
|
+
required: requirements.users.authentication,
|
|
90
|
+
strategy: authStrategy
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
authorization: {
|
|
94
|
+
required: requirements.users.roles,
|
|
95
|
+
strategy: authRoles
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
security: {
|
|
99
|
+
rateLimiting: requirements.api.rateLimiting,
|
|
100
|
+
tenantIsolation: requirements.security.tenantIsolation,
|
|
101
|
+
sensitiveData: requirements.security.sensitiveData,
|
|
102
|
+
controls: threatModel.controls
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
observability: {
|
|
106
|
+
logging,
|
|
107
|
+
metrics,
|
|
108
|
+
tracing,
|
|
109
|
+
structuredJson: true
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
requirements,
|
|
113
|
+
complexity,
|
|
114
|
+
threatModel
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return architectureSpec;
|
|
118
|
+
}
|
|
119
|
+
}
|