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,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — Kiro Adapter
|
|
3
|
+
*
|
|
4
|
+
* Execution adapter for Kiro coding agent runtime.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'node:fs/promises';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import os from 'node:os';
|
|
10
|
+
import { spawn } from 'node:child_process';
|
|
11
|
+
import { AgentAdapter } from './adapter.interface.js';
|
|
12
|
+
|
|
13
|
+
export class KiroAdapter extends AgentAdapter {
|
|
14
|
+
constructor(options = {}) {
|
|
15
|
+
super('kiro', 'Kiro', {
|
|
16
|
+
icon: '🗡️',
|
|
17
|
+
description: 'Kiro autonomous agent and multi-agent runtime',
|
|
18
|
+
capabilities: {
|
|
19
|
+
fileAccess: true,
|
|
20
|
+
terminalAccess: true,
|
|
21
|
+
subagents: true,
|
|
22
|
+
backgroundTasks: true,
|
|
23
|
+
streaming: true,
|
|
24
|
+
toolCalls: true
|
|
25
|
+
},
|
|
26
|
+
...options
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async detectScore(targetDir = process.cwd()) {
|
|
31
|
+
let score = 0;
|
|
32
|
+
|
|
33
|
+
// 1. Environment variables (Active Kiro session/agent environment) (+1000 points)
|
|
34
|
+
if (
|
|
35
|
+
process.env.KIRO ||
|
|
36
|
+
process.env.KIRO_AGENT ||
|
|
37
|
+
process.env.KIRO_SESSION ||
|
|
38
|
+
process.env.KIRO_WORKSPACE ||
|
|
39
|
+
process.env.KIRO_APP_DIR ||
|
|
40
|
+
process.env.KIRO_CONFIG_DIR ||
|
|
41
|
+
process.env.KIRO_PATH
|
|
42
|
+
) {
|
|
43
|
+
score += 1000;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 2. Target Workspace files/folders (.kiro, .kirorules, kiro.json, .kiro.json) (+200 points)
|
|
47
|
+
const indicators = ['.kiro', '.kirorules', 'kiro.json', '.kiro.json'];
|
|
48
|
+
for (const item of indicators) {
|
|
49
|
+
try {
|
|
50
|
+
await fs.access(path.join(targetDir, item));
|
|
51
|
+
score += 200;
|
|
52
|
+
break;
|
|
53
|
+
} catch {}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 3. User Home Directory (~/.kiro, ~/.config/kiro) (+50 points)
|
|
57
|
+
try {
|
|
58
|
+
const home = os.homedir();
|
|
59
|
+
if (home) {
|
|
60
|
+
try {
|
|
61
|
+
await fs.access(path.join(home, '.kiro'));
|
|
62
|
+
score += 50;
|
|
63
|
+
} catch {}
|
|
64
|
+
try {
|
|
65
|
+
await fs.access(path.join(home, '.config', 'kiro'));
|
|
66
|
+
score += 50;
|
|
67
|
+
} catch {}
|
|
68
|
+
}
|
|
69
|
+
} catch {}
|
|
70
|
+
|
|
71
|
+
// 4. macOS Application bundle detection (+30 points)
|
|
72
|
+
if (process.platform === 'darwin') {
|
|
73
|
+
const macApps = [
|
|
74
|
+
'/Applications/Kiro.app',
|
|
75
|
+
path.join(os.homedir() || '', 'Applications', 'Kiro.app'),
|
|
76
|
+
'/Applications/Kiro IDE.app'
|
|
77
|
+
];
|
|
78
|
+
for (const appPath of macApps) {
|
|
79
|
+
try {
|
|
80
|
+
await fs.access(appPath);
|
|
81
|
+
score += 30;
|
|
82
|
+
break;
|
|
83
|
+
} catch {}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 5. Binary CLI in PATH (kiro, kiro-cli, kiro-agent, kiro-ai) (+30 points)
|
|
88
|
+
const binaries = ['kiro', 'kiro-cli', 'kiro-agent', 'kiro-ai'];
|
|
89
|
+
for (const bin of binaries) {
|
|
90
|
+
const isFound = await new Promise((resolve) => {
|
|
91
|
+
try {
|
|
92
|
+
const cmd = process.platform === 'win32' ? 'where' : 'which';
|
|
93
|
+
const proc = spawn(cmd, [bin], { stdio: 'ignore' });
|
|
94
|
+
proc.on('close', (code) => resolve(code === 0));
|
|
95
|
+
proc.on('error', () => resolve(false));
|
|
96
|
+
} catch {
|
|
97
|
+
resolve(false);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
if (isFound) {
|
|
101
|
+
score += 30;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return score;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async detect(targetDir = process.cwd()) {
|
|
110
|
+
const score = await this.detectScore(targetDir);
|
|
111
|
+
return score > 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async execute(task, context = {}) {
|
|
115
|
+
const { emit = () => {}, signal } = context;
|
|
116
|
+
|
|
117
|
+
if (signal?.aborted) {
|
|
118
|
+
throw new Error(`Task ${task.id} cancelled before start`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
await emit('tool.invoked', `Kiro agent executing task: ${task.title}`);
|
|
122
|
+
|
|
123
|
+
if (context.executeTaskHandler) {
|
|
124
|
+
return await context.executeTaskHandler(task, emit);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
await new Promise(r => setTimeout(r, 200));
|
|
128
|
+
return {
|
|
129
|
+
success: true,
|
|
130
|
+
provider: this.id,
|
|
131
|
+
taskId: task.id
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — Provider Registry & Dynamic Strategy Engine
|
|
3
|
+
*
|
|
4
|
+
* Manages coding agent providers, executes environment scans, and resolves
|
|
5
|
+
* the optimal adapter based on task requirements and selected runtime strategies.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { GenericAdapter } from './generic.js';
|
|
9
|
+
import { ClaudeCodeAdapter } from './claude-code.js';
|
|
10
|
+
import { CodexAdapter } from './codex.js';
|
|
11
|
+
import { CursorAdapter } from './cursor.js';
|
|
12
|
+
import { KiroAdapter } from './kiro.js';
|
|
13
|
+
import { AntigravityAdapter } from './antigravity.js';
|
|
14
|
+
|
|
15
|
+
export class ProviderRegistry {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.adapters = new Map();
|
|
18
|
+
this.detectedCache = new Map();
|
|
19
|
+
this.lastScanTime = 0;
|
|
20
|
+
|
|
21
|
+
// Register built-in providers
|
|
22
|
+
this.registerAdapter(new GenericAdapter());
|
|
23
|
+
this.registerAdapter(new ClaudeCodeAdapter());
|
|
24
|
+
this.registerAdapter(new CodexAdapter());
|
|
25
|
+
this.registerAdapter(new CursorAdapter());
|
|
26
|
+
this.registerAdapter(new KiroAdapter());
|
|
27
|
+
this.registerAdapter(new AntigravityAdapter());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
registerAdapter(adapter) {
|
|
31
|
+
if (!adapter?.id) {
|
|
32
|
+
throw new Error('Adapter must have a unique id');
|
|
33
|
+
}
|
|
34
|
+
this.adapters.set(adapter.id, adapter);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getAdapter(id) {
|
|
38
|
+
return this.adapters.get(id) || null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getAllAdapters() {
|
|
42
|
+
return Array.from(this.adapters.values());
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Scans system to detect available providers and determine the active runtime
|
|
47
|
+
* @param {boolean} forceRefresh
|
|
48
|
+
* @param {string} targetDir
|
|
49
|
+
* @returns {Promise<{ activeProvider: string, activeProviderName: string, activeProviderIcon: string, activeProviderDescription: string, available: import('./adapter.interface.js').AgentAdapter[], missing: import('./adapter.interface.js').AgentAdapter[] }>}
|
|
50
|
+
*/
|
|
51
|
+
async scanEnvironment(forceRefresh = false, targetDir = process.cwd()) {
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
if (!forceRefresh && now - this.lastScanTime < 4000 && this.detectedCache.size > 0 && this.lastScanResult) {
|
|
54
|
+
return this.lastScanResult;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const availableWithScores = [];
|
|
58
|
+
const missing = [];
|
|
59
|
+
|
|
60
|
+
for (const adapter of this.adapters.values()) {
|
|
61
|
+
try {
|
|
62
|
+
const score = typeof adapter.detectScore === 'function'
|
|
63
|
+
? await adapter.detectScore(targetDir)
|
|
64
|
+
: ((await adapter.detect(targetDir)) ? 100 : 0);
|
|
65
|
+
|
|
66
|
+
this.detectedCache.set(adapter.id, score > 0);
|
|
67
|
+
if (score > 0) {
|
|
68
|
+
availableWithScores.push({ adapter, score });
|
|
69
|
+
} else {
|
|
70
|
+
missing.push(adapter);
|
|
71
|
+
}
|
|
72
|
+
} catch {
|
|
73
|
+
this.detectedCache.set(adapter.id, false);
|
|
74
|
+
missing.push(adapter);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Sort available adapters by confidence score descending
|
|
79
|
+
availableWithScores.sort((a, b) => {
|
|
80
|
+
// Prioritize higher score
|
|
81
|
+
if (b.score !== a.score) return b.score - a.score;
|
|
82
|
+
// If score is equal, prioritize Antigravity / Kiro / Claude over generic
|
|
83
|
+
if (a.adapter.id === 'generic') return 1;
|
|
84
|
+
if (b.adapter.id === 'generic') return -1;
|
|
85
|
+
return 0;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const available = availableWithScores.map(item => item.adapter);
|
|
89
|
+
const top = available.find(a => a.id !== 'generic') || available[0] || this.getAdapter('generic');
|
|
90
|
+
|
|
91
|
+
this.lastScanTime = now;
|
|
92
|
+
this.lastScanResult = {
|
|
93
|
+
activeProvider: top?.id || 'generic',
|
|
94
|
+
activeProviderName: top?.name || 'Generic CLI Runner',
|
|
95
|
+
activeProviderIcon: top?.icon || '💻',
|
|
96
|
+
activeProviderDescription: top?.description || '',
|
|
97
|
+
available,
|
|
98
|
+
missing
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return this.lastScanResult;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Selects the best adapter for a given task based on strategy
|
|
106
|
+
* @param {import('../protocol/task.js').AgentTask} task
|
|
107
|
+
* @param {string} strategy - 'auto' | 'hybrid' | specific provider id
|
|
108
|
+
*/
|
|
109
|
+
async getBestAgent(task, strategy = 'auto') {
|
|
110
|
+
// If specific adapter explicitly requested
|
|
111
|
+
if (strategy && strategy !== 'auto' && strategy !== 'hybrid') {
|
|
112
|
+
const explicit = this.getAdapter(strategy);
|
|
113
|
+
if (explicit) return explicit;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Check if task itself specifies an assigned provider
|
|
117
|
+
if (task?.assignedProvider) {
|
|
118
|
+
const assigned = this.getAdapter(task.assignedProvider);
|
|
119
|
+
if (assigned) return assigned;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const { activeProvider, available } = await this.scanEnvironment();
|
|
123
|
+
|
|
124
|
+
if (strategy === 'hybrid') {
|
|
125
|
+
// Hybrid crew strategy:
|
|
126
|
+
// - Design / Frontend -> Claude Code / Cursor / Antigravity
|
|
127
|
+
// - Backend / Data -> Codex / Antigravity / Kiro
|
|
128
|
+
// - QA / Review -> Claude Code / Generic / Antigravity
|
|
129
|
+
if (task.agent === 'frontend' || task.agent === 'creativeDirector') {
|
|
130
|
+
const preferred = available.find(a => a.id === 'claude-code' || a.id === 'cursor' || a.id === 'antigravity');
|
|
131
|
+
if (preferred) return preferred;
|
|
132
|
+
} else if (task.agent === 'backend' || task.agent === 'database') {
|
|
133
|
+
const preferred = available.find(a => a.id === 'codex' || a.id === 'antigravity' || a.id === 'kiro');
|
|
134
|
+
if (preferred) return preferred;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// In 'auto' mode: Use the top-scored active provider
|
|
139
|
+
if (activeProvider) {
|
|
140
|
+
const activeAdapter = this.getAdapter(activeProvider);
|
|
141
|
+
if (activeAdapter) return activeAdapter;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (available.length > 0) {
|
|
145
|
+
return available[0];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return this.getAdapter('generic');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — Architecture Complexity Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Computes multi-dimensional complexity scores and prevents over-engineering
|
|
5
|
+
* by ensuring architectural choices match actual application constraints.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class ComplexityAnalyzer {
|
|
9
|
+
/**
|
|
10
|
+
* Calculate complexity score across 6 architectural dimensions
|
|
11
|
+
* @param {object} requirements - SystemRequirementsModel
|
|
12
|
+
* @param {object} ast - Semantic Project AST
|
|
13
|
+
* @returns {object} Complexity Assessment
|
|
14
|
+
*/
|
|
15
|
+
static analyze(requirements = {}, ast = {}) {
|
|
16
|
+
const app = requirements.application || {};
|
|
17
|
+
const users = requirements.users || {};
|
|
18
|
+
const data = requirements.data || {};
|
|
19
|
+
const api = requirements.api || {};
|
|
20
|
+
const security = requirements.security || {};
|
|
21
|
+
const performance = requirements.performance || {};
|
|
22
|
+
const jobs = requirements.backgroundJobs || {};
|
|
23
|
+
|
|
24
|
+
const entities = ast.entities || [];
|
|
25
|
+
const workflows = ast.workflows || [];
|
|
26
|
+
const operations = ast.operations || [];
|
|
27
|
+
|
|
28
|
+
// 1. Domain Complexity (0–25)
|
|
29
|
+
let domainScore = 5;
|
|
30
|
+
if (entities.length > 5) domainScore += 5;
|
|
31
|
+
if (entities.length > 10) domainScore += 5;
|
|
32
|
+
if (workflows.length > 3) domainScore += 5;
|
|
33
|
+
if (users.roles && users.organizations) domainScore += 5;
|
|
34
|
+
|
|
35
|
+
// 2. Traffic & Concurrency Complexity (0–20)
|
|
36
|
+
let trafficScore = 3;
|
|
37
|
+
if (app.expectedScale === 'medium') trafficScore += 5;
|
|
38
|
+
if (app.expectedScale === 'high') trafficScore += 12;
|
|
39
|
+
if (performance.realTime) trafficScore += 5;
|
|
40
|
+
|
|
41
|
+
// 3. Data & Storage Complexity (0–20)
|
|
42
|
+
let dataScore = 4;
|
|
43
|
+
if (data.transactions) dataScore += 5;
|
|
44
|
+
if (data.search) dataScore += 3;
|
|
45
|
+
if (data.auditLog) dataScore += 3;
|
|
46
|
+
if (security.tenantIsolation) dataScore += 5;
|
|
47
|
+
|
|
48
|
+
// 4. Integration & Background Processing (0–15)
|
|
49
|
+
let integrationScore = 2;
|
|
50
|
+
if (jobs.required) integrationScore += 5;
|
|
51
|
+
if (jobs.tasks && jobs.tasks.length > 2) integrationScore += 4;
|
|
52
|
+
if (api.public) integrationScore += 4;
|
|
53
|
+
|
|
54
|
+
// 5. Reliability & Availability Requirements (0–10)
|
|
55
|
+
let reliabilityScore = 2;
|
|
56
|
+
if (app.availability === '99.9%') reliabilityScore += 3;
|
|
57
|
+
if (app.availability === '99.99%') reliabilityScore += 6;
|
|
58
|
+
if (data.transactions) reliabilityScore += 2;
|
|
59
|
+
|
|
60
|
+
// 6. Security Complexity (0–10)
|
|
61
|
+
let securityScore = 2;
|
|
62
|
+
if (security.tenantIsolation) securityScore += 3;
|
|
63
|
+
if (security.sensitiveData) securityScore += 3;
|
|
64
|
+
if (security.auditLogging) securityScore += 2;
|
|
65
|
+
|
|
66
|
+
const totalScore = domainScore + trafficScore + dataScore + integrationScore + reliabilityScore + securityScore;
|
|
67
|
+
|
|
68
|
+
// Determine Tier
|
|
69
|
+
let tier = 'low';
|
|
70
|
+
let recommendedStyle = 'modular-monolith';
|
|
71
|
+
let allowedInfrastructure = ['postgresql', 'sqlite', 'in-memory-cache'];
|
|
72
|
+
let disallowedInfrastructure = ['microservices', 'kubernetes', 'kafka', 'service-mesh'];
|
|
73
|
+
|
|
74
|
+
if (totalScore >= 60) {
|
|
75
|
+
tier = 'high';
|
|
76
|
+
recommendedStyle = 'distributed-modular-services';
|
|
77
|
+
allowedInfrastructure.push('redis', 'bullmq', 'cdn-edge', 'worker-cluster');
|
|
78
|
+
if (totalScore > 80) {
|
|
79
|
+
disallowedInfrastructure = []; // Complex requirements may justify advanced distributed infra
|
|
80
|
+
}
|
|
81
|
+
} else if (totalScore >= 35) {
|
|
82
|
+
tier = 'medium';
|
|
83
|
+
recommendedStyle = 'modular-monolith-with-workers';
|
|
84
|
+
allowedInfrastructure.push('redis', 'bullmq');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
totalScore,
|
|
89
|
+
tier, // 'low' | 'medium' | 'high'
|
|
90
|
+
recommendedStyle,
|
|
91
|
+
dimensions: {
|
|
92
|
+
domain: domainScore,
|
|
93
|
+
traffic: trafficScore,
|
|
94
|
+
data: dataScore,
|
|
95
|
+
integration: integrationScore,
|
|
96
|
+
reliability: reliabilityScore,
|
|
97
|
+
security: securityScore
|
|
98
|
+
},
|
|
99
|
+
allowedInfrastructure,
|
|
100
|
+
disallowedInfrastructure,
|
|
101
|
+
summary: `Complexity score ${totalScore}/100 (${tier} complexity). Recommended architecture: ${recommendedStyle}.`
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — System Requirement Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Analyzes natural language intent and project AST to extract a structured,
|
|
5
|
+
* machine-verifiable SystemRequirementsModel without domain hardcoding.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class RequirementAnalyzer {
|
|
9
|
+
/**
|
|
10
|
+
* Extract comprehensive backend requirements from prompt & AST
|
|
11
|
+
* @param {string} prompt
|
|
12
|
+
* @param {object} ast
|
|
13
|
+
* @returns {object} SystemRequirementsModel
|
|
14
|
+
*/
|
|
15
|
+
static analyze(prompt = '', ast = {}) {
|
|
16
|
+
const rawPrompt = String(prompt).toLowerCase();
|
|
17
|
+
const domain = (ast.domain || '').toLowerCase();
|
|
18
|
+
const entities = ast.entities || [];
|
|
19
|
+
const workflows = ast.workflows || [];
|
|
20
|
+
const operations = ast.operations || [];
|
|
21
|
+
|
|
22
|
+
// 1. Application Scale & Multi-tenancy Inferences
|
|
23
|
+
const isMultiTenant = Boolean(
|
|
24
|
+
rawPrompt.includes('tenant') ||
|
|
25
|
+
rawPrompt.includes('organization') ||
|
|
26
|
+
rawPrompt.includes('workspace') ||
|
|
27
|
+
rawPrompt.includes('b2b') ||
|
|
28
|
+
rawPrompt.includes('team') ||
|
|
29
|
+
entities.some(e => ['Organization', 'Workspace', 'Tenant', 'Team', 'Account'].includes(e.name))
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const isHighScale = Boolean(
|
|
33
|
+
rawPrompt.includes('high throughput') ||
|
|
34
|
+
rawPrompt.includes('streaming') ||
|
|
35
|
+
rawPrompt.includes('million') ||
|
|
36
|
+
rawPrompt.includes('distributed') ||
|
|
37
|
+
rawPrompt.includes('large scale') ||
|
|
38
|
+
rawPrompt.includes('real-time analytics')
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const scale = isHighScale ? 'high' : (isMultiTenant ? 'medium' : 'low');
|
|
42
|
+
|
|
43
|
+
// 2. User & Authentication Inferences
|
|
44
|
+
const hasAuth = Boolean(
|
|
45
|
+
rawPrompt.includes('login') ||
|
|
46
|
+
rawPrompt.includes('auth') ||
|
|
47
|
+
rawPrompt.includes('user') ||
|
|
48
|
+
rawPrompt.includes('account') ||
|
|
49
|
+
rawPrompt.includes('sign in') ||
|
|
50
|
+
rawPrompt.includes('permission') ||
|
|
51
|
+
rawPrompt.includes('role') ||
|
|
52
|
+
isMultiTenant ||
|
|
53
|
+
(ast.actors && ast.actors.length > 1)
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const hasRoles = Boolean(
|
|
57
|
+
rawPrompt.includes('role') ||
|
|
58
|
+
rawPrompt.includes('admin') ||
|
|
59
|
+
rawPrompt.includes('rbac') ||
|
|
60
|
+
rawPrompt.includes('permission') ||
|
|
61
|
+
(ast.actors && ast.actors.length > 1)
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// 3. Data Inferences
|
|
65
|
+
const hasTransactions = Boolean(
|
|
66
|
+
rawPrompt.includes('payment') ||
|
|
67
|
+
rawPrompt.includes('checkout') ||
|
|
68
|
+
rawPrompt.includes('transfer') ||
|
|
69
|
+
rawPrompt.includes('order') ||
|
|
70
|
+
rawPrompt.includes('booking') ||
|
|
71
|
+
rawPrompt.includes('reservation') ||
|
|
72
|
+
rawPrompt.includes('inventory') ||
|
|
73
|
+
rawPrompt.includes('financial') ||
|
|
74
|
+
rawPrompt.includes('ledger') ||
|
|
75
|
+
rawPrompt.includes('atomic') ||
|
|
76
|
+
workflows.some(w => /pay|order|book|reserve|transfer|transact/i.test(w.name || ''))
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const hasSearch = Boolean(
|
|
80
|
+
rawPrompt.includes('search') ||
|
|
81
|
+
rawPrompt.includes('filter') ||
|
|
82
|
+
rawPrompt.includes('catalog') ||
|
|
83
|
+
rawPrompt.includes('browse') ||
|
|
84
|
+
operations.some(op => (op.path || '').includes('search'))
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// 4. API Inferences
|
|
88
|
+
const isPublicAPI = Boolean(
|
|
89
|
+
rawPrompt.includes('public api') ||
|
|
90
|
+
rawPrompt.includes('webhook') ||
|
|
91
|
+
rawPrompt.includes('developer platform') ||
|
|
92
|
+
rawPrompt.includes('sdk')
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const rateLimiting = Boolean(
|
|
96
|
+
hasAuth ||
|
|
97
|
+
isPublicAPI ||
|
|
98
|
+
rawPrompt.includes('rate limit') ||
|
|
99
|
+
isMultiTenant
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// 5. Security Inferences
|
|
103
|
+
const hasSensitiveData = Boolean(
|
|
104
|
+
rawPrompt.includes('health') ||
|
|
105
|
+
rawPrompt.includes('patient') ||
|
|
106
|
+
rawPrompt.includes('emr') ||
|
|
107
|
+
rawPrompt.includes('payment') ||
|
|
108
|
+
rawPrompt.includes('credit card') ||
|
|
109
|
+
rawPrompt.includes('pii') ||
|
|
110
|
+
rawPrompt.includes('contract') ||
|
|
111
|
+
rawPrompt.includes('legal') ||
|
|
112
|
+
rawPrompt.includes('secret') ||
|
|
113
|
+
rawPrompt.includes('password')
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const auditLogging = Boolean(
|
|
117
|
+
isMultiTenant ||
|
|
118
|
+
hasSensitiveData ||
|
|
119
|
+
hasTransactions ||
|
|
120
|
+
rawPrompt.includes('audit') ||
|
|
121
|
+
rawPrompt.includes('compliance')
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// 6. Performance & Asynchronous Jobs Inferences
|
|
125
|
+
const isReadHeavy = !rawPrompt.includes('write intensive') && !rawPrompt.includes('ingest');
|
|
126
|
+
const isRealTime = Boolean(
|
|
127
|
+
rawPrompt.includes('realtime') ||
|
|
128
|
+
rawPrompt.includes('real-time') ||
|
|
129
|
+
rawPrompt.includes('websocket') ||
|
|
130
|
+
rawPrompt.includes('live') ||
|
|
131
|
+
rawPrompt.includes('chat') ||
|
|
132
|
+
rawPrompt.includes('collaboration')
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const backgroundJobs = Boolean(
|
|
136
|
+
rawPrompt.includes('job') ||
|
|
137
|
+
rawPrompt.includes('queue') ||
|
|
138
|
+
rawPrompt.includes('worker') ||
|
|
139
|
+
rawPrompt.includes('email') ||
|
|
140
|
+
rawPrompt.includes('export') ||
|
|
141
|
+
rawPrompt.includes('import') ||
|
|
142
|
+
rawPrompt.includes('report') ||
|
|
143
|
+
rawPrompt.includes('video') ||
|
|
144
|
+
rawPrompt.includes('transcription') ||
|
|
145
|
+
rawPrompt.includes('render') ||
|
|
146
|
+
rawPrompt.includes('batch') ||
|
|
147
|
+
rawPrompt.includes('notification')
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
application: {
|
|
152
|
+
name: ast.appName || 'Application',
|
|
153
|
+
domain: domain || 'general',
|
|
154
|
+
type: isMultiTenant ? 'multi-tenant SaaS' : (isHighScale ? 'high-throughput system' : 'modular application'),
|
|
155
|
+
expectedScale: scale,
|
|
156
|
+
availability: isHighScale ? '99.99%' : (isMultiTenant ? '99.9%' : '99.5%')
|
|
157
|
+
},
|
|
158
|
+
users: {
|
|
159
|
+
authentication: hasAuth,
|
|
160
|
+
strategy: hasAuth ? (isMultiTenant ? 'session' : 'session') : 'none',
|
|
161
|
+
roles: hasRoles,
|
|
162
|
+
organizations: isMultiTenant
|
|
163
|
+
},
|
|
164
|
+
data: {
|
|
165
|
+
relational: true,
|
|
166
|
+
transactions: hasTransactions,
|
|
167
|
+
search: hasSearch,
|
|
168
|
+
softDelete: isMultiTenant || hasSensitiveData,
|
|
169
|
+
auditLog: auditLogging
|
|
170
|
+
},
|
|
171
|
+
api: {
|
|
172
|
+
style: 'REST',
|
|
173
|
+
versioning: true,
|
|
174
|
+
public: isPublicAPI,
|
|
175
|
+
rateLimiting,
|
|
176
|
+
errorFormat: 'RFC-7807'
|
|
177
|
+
},
|
|
178
|
+
security: {
|
|
179
|
+
sensitiveData: hasSensitiveData,
|
|
180
|
+
tenantIsolation: isMultiTenant,
|
|
181
|
+
auditLogging,
|
|
182
|
+
strictValidation: true,
|
|
183
|
+
denyByDefault: true
|
|
184
|
+
},
|
|
185
|
+
performance: {
|
|
186
|
+
readHeavy: isReadHeavy,
|
|
187
|
+
realTime: isRealTime,
|
|
188
|
+
caching: hasSearch || isReadHeavy || isMultiTenant,
|
|
189
|
+
paginationStrategy: (isHighScale || hasSearch) ? 'cursor' : 'offset'
|
|
190
|
+
},
|
|
191
|
+
backgroundJobs: {
|
|
192
|
+
required: backgroundJobs,
|
|
193
|
+
tasks: this.extractJobTasks(rawPrompt)
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Helper: Extracts discrete background job types
|
|
200
|
+
*/
|
|
201
|
+
static extractJobTasks(prompt) {
|
|
202
|
+
const tasks = [];
|
|
203
|
+
if (prompt.includes('email') || prompt.includes('notification')) tasks.push('send-notifications');
|
|
204
|
+
if (prompt.includes('export') || prompt.includes('report')) tasks.push('generate-reports');
|
|
205
|
+
if (prompt.includes('import') || prompt.includes('csv')) tasks.push('batch-import');
|
|
206
|
+
if (prompt.includes('video') || prompt.includes('image') || prompt.includes('transcription')) tasks.push('media-processing');
|
|
207
|
+
if (prompt.includes('webhook')) tasks.push('webhook-dispatch');
|
|
208
|
+
if (tasks.length === 0 && (prompt.includes('worker') || prompt.includes('queue'))) {
|
|
209
|
+
tasks.push('async-task-worker');
|
|
210
|
+
}
|
|
211
|
+
return tasks;
|
|
212
|
+
}
|
|
213
|
+
}
|