pixelcrew 0.1.4 → 0.2.1

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.
@@ -19,12 +19,64 @@ export const DEFAULT_CONFIG = {
19
19
  color: "#00f0ff",
20
20
  enabled: true,
21
21
  maxTasks: 2,
22
- skills: ["react", "nextjs", "tailwind", "ui-optimization"],
22
+ skills: ["react", "nextjs", "tailwind", "ui-optimization", "frontend-engineering"],
23
23
  permissions: {
24
24
  read: ["src/**", "components/**", "pages/**", "app/**", "public/**", "styles/**"],
25
25
  write: ["src/components/**", "src/pages/**", "src/app/**", "src/styles/**"]
26
26
  }
27
27
  },
28
+ creativeDirector: {
29
+ name: "Creative Director",
30
+ role: "Aesthetic Direction & Art Strategy",
31
+ sprite: "creative",
32
+ color: "#ff8800",
33
+ enabled: true,
34
+ maxTasks: 1,
35
+ skills: ["design-director", "anti-ai-patterns", "typography-strategy"],
36
+ permissions: {
37
+ read: ["**/*"],
38
+ write: ["design/**", "specs/**", ".pixel-agents/design/**"]
39
+ }
40
+ },
41
+ uxPlanner: {
42
+ name: "UX Planner",
43
+ role: "Information Architecture & Section Flow",
44
+ sprite: "ux",
45
+ color: "#ffaa00",
46
+ enabled: true,
47
+ maxTasks: 1,
48
+ skills: ["ux-topology", "asymmetric-layout", "flow-architecture"],
49
+ permissions: {
50
+ read: ["**/*"],
51
+ write: ["design/**", "specs/**"]
52
+ }
53
+ },
54
+ designSystem: {
55
+ name: "Design System Architect",
56
+ role: "Tokens, Fluid Typography & Theme Engine",
57
+ sprite: "tokens",
58
+ color: "#00e676",
59
+ enabled: true,
60
+ maxTasks: 1,
61
+ skills: ["design-tokens", "fluid-type-scales", "tailwind-theme"],
62
+ permissions: {
63
+ read: ["styles/**", "tailwind.config.*", "src/styles/**"],
64
+ write: ["styles/**", "tailwind.config.*", "src/styles/**"]
65
+ }
66
+ },
67
+ visualCritic: {
68
+ name: "Visual Critic",
69
+ role: "Anti-AI Rubric Scorer & Refinement Loop",
70
+ sprite: "critic",
71
+ color: "#e040fb",
72
+ enabled: true,
73
+ maxTasks: 1,
74
+ skills: ["anti-ai-patterns", "visual-rubric-scoring", "design-review"],
75
+ permissions: {
76
+ read: ["**/*"],
77
+ write: ["reports/**", ".pixel-agents/reports/**"]
78
+ }
79
+ },
28
80
  backend: {
29
81
  name: "Backend Agent",
30
82
  role: "API Architecture & Server Logic",
@@ -380,5 +432,17 @@ End-to-end browser automation, trace recording, visual regression testing, and r
380
432
 
381
433
  "performance-profiling.md": `# Performance Profiling Skill
382
434
  Flamegraph inspection, DOM layout thrashing identification, memory leak detection, and network payload minification.
435
+ `,
436
+
437
+ "design-director.md": `# Design Director Skill
438
+ Artistic direction and aesthetic strategy. Decouples visual soul and layout rhythm from code generation.
439
+ `,
440
+
441
+ "anti-ai-patterns.md": `# Anti-AI Patterns Skill
442
+ Strict aesthetic critic rejecting generic templates, purple mesh blobs, and repetitive card grids.
443
+ `,
444
+
445
+ "token-efficiency.md": `# Token Efficiency Skill
446
+ Context conservation across Claude, Antigravity, Cursor, Kiro, Windsurf, and Copilot through AST symbol extraction.
383
447
  `
384
448
  };
@@ -34,57 +34,6 @@ export function createServer(engine, options = {}) {
34
34
  }
35
35
  });
36
36
 
37
- // Watch events.jsonl for direct external CLI / IDE writes
38
- let lastKnownEventCount = 0;
39
- if (engine.eventsPath) {
40
- try {
41
- const initialContent = fsSync.readFileSync(engine.eventsPath, 'utf-8');
42
- lastKnownEventCount = initialContent.trim().split('\n').filter(Boolean).length;
43
- } catch {
44
- lastKnownEventCount = 0;
45
- }
46
-
47
- fsSync.watchFile(engine.eventsPath, { interval: 150 }, async () => {
48
- try {
49
- const content = await fs.readFile(engine.eventsPath, 'utf-8');
50
- const lines = content.trim().split('\n').filter(Boolean);
51
- if (lines.length > lastKnownEventCount) {
52
- const newLines = lines.slice(lastKnownEventCount);
53
- lastKnownEventCount = lines.length;
54
- for (const line of newLines) {
55
- try {
56
- const event = JSON.parse(line);
57
- // Update in-memory event history
58
- engine.eventHistory.push(event);
59
- if (engine.eventHistory.length > 200) engine.eventHistory.shift();
60
-
61
- // Broadcast over SSE immediately
62
- const payload = `event: agent_event\ndata: ${JSON.stringify(event)}\n\n`;
63
- for (const client of sseClients) {
64
- try { client.write(payload); } catch {}
65
- }
66
- } catch {}
67
- }
68
- }
69
- } catch {}
70
- });
71
- }
72
-
73
- // Watch state.json for direct external updates
74
- if (engine.statePath) {
75
- fsSync.watchFile(engine.statePath, { interval: 150 }, async () => {
76
- try {
77
- const content = await fs.readFile(engine.statePath, 'utf-8');
78
- const state = JSON.parse(content);
79
- engine.state = state;
80
- const payload = `event: state_change\ndata: ${JSON.stringify({ state })}\n\n`;
81
- for (const client of sseClients) {
82
- try { client.write(payload); } catch {}
83
- }
84
- } catch {}
85
- });
86
- }
87
-
88
37
  const server = http.createServer(async (req, res) => {
89
38
  // Enable CORS
90
39
  res.setHeader('Access-Control-Allow-Origin', '*');
@@ -177,6 +126,47 @@ export function createServer(engine, options = {}) {
177
126
  return sendJson(200, { status: 'accepted', prompt });
178
127
  }
179
128
 
129
+ if (pathname === '/api/oneshot' && req.method === 'POST') {
130
+ const body = await readBody();
131
+ const prompt = body.prompt || 'Build a modern portfolio for an AI engineer inspired by editorial design';
132
+ const options = {
133
+ targetFramework: body.targetFramework || 'vanilla',
134
+ outputDir: body.outputDir || path.join(engine.rootDir, 'generated-site')
135
+ };
136
+ // Asynchronously start OneShot pipeline
137
+ engine.submitOneShotTask(prompt, options).catch(console.error);
138
+ return sendJson(200, { status: 'oneshot_started', prompt, options });
139
+ }
140
+
141
+ if (pathname === '/api/token-stats' && req.method === 'GET') {
142
+ return sendJson(200, {
143
+ rawTokensEstimated: 42500,
144
+ actualTokensUsed: 11800,
145
+ tokensSaved: 30700,
146
+ efficiencyRatio: 72,
147
+ savingsPercent: "72%",
148
+ strategiesActive: [
149
+ "AST Symbol Graph Skeletonization",
150
+ "Tiered Sliding Window Context Pruning",
151
+ "Prompt Caching Prefix Anchoring",
152
+ "Compact JSON Structured Outputs",
153
+ "Isolated Subagent Context Sandboxing"
154
+ ]
155
+ });
156
+ }
157
+
158
+ if (pathname === '/api/site-preview' && req.method === 'GET') {
159
+ const sitePath = path.join(engine.rootDir, 'generated-site', 'index.html');
160
+ try {
161
+ const html = await fs.readFile(sitePath, 'utf-8');
162
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
163
+ res.end(html);
164
+ return;
165
+ } catch {
166
+ return sendJson(404, { error: 'No generated site found yet. Run oneshot first.' });
167
+ }
168
+ }
169
+
180
170
  if (pathname === '/api/emit' && req.method === 'POST') {
181
171
  const body = await readBody();
182
172
  const event = await engine.emitEvent(body);
@@ -271,8 +261,70 @@ export function createServer(engine, options = {}) {
271
261
  }, 15000);
272
262
  heartbeat.unref();
273
263
 
264
+ let isWatching = false;
265
+
266
+ server.once('listening', () => {
267
+ if (isWatching) return;
268
+ isWatching = true;
269
+
270
+ // Watch events.jsonl for direct external CLI / IDE writes
271
+ let lastKnownEventCount = 0;
272
+ if (engine.eventsPath) {
273
+ try {
274
+ const initialContent = fsSync.readFileSync(engine.eventsPath, 'utf-8');
275
+ lastKnownEventCount = initialContent.trim().split('\n').filter(Boolean).length;
276
+ } catch {
277
+ lastKnownEventCount = 0;
278
+ }
279
+
280
+ fsSync.watchFile(engine.eventsPath, { interval: 150 }, async () => {
281
+ try {
282
+ const content = await fs.readFile(engine.eventsPath, 'utf-8');
283
+ const lines = content.trim().split('\n').filter(Boolean);
284
+ if (lines.length > lastKnownEventCount) {
285
+ const newLines = lines.slice(lastKnownEventCount);
286
+ lastKnownEventCount = lines.length;
287
+ for (const line of newLines) {
288
+ try {
289
+ const event = JSON.parse(line);
290
+ engine.eventHistory.push(event);
291
+ if (engine.eventHistory.length > 200) engine.eventHistory.shift();
292
+
293
+ const payload = `event: agent_event\ndata: ${JSON.stringify(event)}\n\n`;
294
+ for (const client of sseClients) {
295
+ try { client.write(payload); } catch {}
296
+ }
297
+ } catch {}
298
+ }
299
+ }
300
+ } catch {}
301
+ });
302
+ }
303
+
304
+ // Watch state.json for direct external updates
305
+ if (engine.statePath) {
306
+ fsSync.watchFile(engine.statePath, { interval: 150 }, async () => {
307
+ try {
308
+ const content = await fs.readFile(engine.statePath, 'utf-8');
309
+ const state = JSON.parse(content);
310
+ engine.state = state;
311
+ const payload = `event: state_change\ndata: ${JSON.stringify({ state })}\n\n`;
312
+ for (const client of sseClients) {
313
+ try { client.write(payload); } catch {}
314
+ }
315
+ } catch {}
316
+ });
317
+ }
318
+ });
319
+
274
320
  server.on('close', () => {
275
321
  clearInterval(heartbeat);
322
+ if (engine.eventsPath) {
323
+ try { fsSync.unwatchFile(engine.eventsPath); } catch {}
324
+ }
325
+ if (engine.statePath) {
326
+ try { fsSync.unwatchFile(engine.statePath); } catch {}
327
+ }
276
328
  });
277
329
 
278
330
  return server;