pixelcrew 0.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.
- package/LICENSE +190 -0
- package/README.md +341 -0
- package/bin/pixel-agents.js +372 -0
- package/package.json +47 -0
- package/src/dashboard/app.js +1047 -0
- package/src/dashboard/index.html +232 -0
- package/src/dashboard/styles.css +892 -0
- package/src/index.js +3 -0
- package/src/orchestrator/engine.js +652 -0
- package/src/scaffold/analyzer.js +398 -0
- package/src/scaffold/init.js +155 -0
- package/src/scaffold/templates.js +384 -0
- package/src/server/server.js +232 -0
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Deep static codebase analyzer that detects frameworks, database/ORMs,
|
|
6
|
+
* architectures, languages, and directory layouts to tailor agent skills and permissions.
|
|
7
|
+
*/
|
|
8
|
+
export async function analyzeCodebase(targetDir = process.cwd()) {
|
|
9
|
+
const profile = {
|
|
10
|
+
projectName: path.basename(targetDir),
|
|
11
|
+
languages: [],
|
|
12
|
+
frameworks: [],
|
|
13
|
+
backend: [],
|
|
14
|
+
database: [],
|
|
15
|
+
testing: [],
|
|
16
|
+
auth: [],
|
|
17
|
+
styling: [],
|
|
18
|
+
packageManager: 'npm',
|
|
19
|
+
directories: [],
|
|
20
|
+
files: [],
|
|
21
|
+
recommendedSkills: [],
|
|
22
|
+
agentSpecializations: {}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Helper to safely check if file or dir exists
|
|
26
|
+
const exists = async (relPath) => {
|
|
27
|
+
try {
|
|
28
|
+
await fs.access(path.join(targetDir, relPath));
|
|
29
|
+
return true;
|
|
30
|
+
} catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Helper to read and parse JSON
|
|
36
|
+
const readJson = async (relPath) => {
|
|
37
|
+
try {
|
|
38
|
+
const data = await fs.readFile(path.join(targetDir, relPath), 'utf-8');
|
|
39
|
+
return JSON.parse(data);
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Helper to read file text
|
|
46
|
+
const readText = async (relPath) => {
|
|
47
|
+
try {
|
|
48
|
+
return await fs.readFile(path.join(targetDir, relPath), 'utf-8');
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// 1. Scan Top-Level Directories
|
|
55
|
+
try {
|
|
56
|
+
const entries = await fs.readdir(targetDir, { withFileTypes: true });
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
|
|
59
|
+
profile.directories.push(entry.name);
|
|
60
|
+
} else if (entry.isFile()) {
|
|
61
|
+
profile.files.push(entry.name);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} catch {
|
|
65
|
+
// ignore
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 2. Node.js & JavaScript/TypeScript Ecosystem Detection
|
|
69
|
+
const dirName = path.basename(targetDir);
|
|
70
|
+
const GENERIC_NAMES = new Set([
|
|
71
|
+
'next_temp', 'next-temp', 'nextjs-temp', 'my-app', 'next-app', 'react-app',
|
|
72
|
+
'app', 'template', 'starter', 'boilerplate', 'untitled', 'temp', 'tmp', 'project',
|
|
73
|
+
'create-next-app', 'vite-project', 'frontend', 'backend', 'demo', 'sample'
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
const pkg = await readJson('package.json');
|
|
77
|
+
if (pkg && pkg.name && !GENERIC_NAMES.has(pkg.name.toLowerCase())) {
|
|
78
|
+
profile.projectName = pkg.name;
|
|
79
|
+
} else {
|
|
80
|
+
profile.projectName = dirName;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (pkg) {
|
|
84
|
+
const allDeps = {
|
|
85
|
+
...(pkg.dependencies || {}),
|
|
86
|
+
...(pkg.devDependencies || {})
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// Languages
|
|
90
|
+
if (allDeps.typescript || await exists('tsconfig.json')) {
|
|
91
|
+
profile.languages.push('TypeScript');
|
|
92
|
+
}
|
|
93
|
+
profile.languages.push('JavaScript');
|
|
94
|
+
|
|
95
|
+
// Frontend Frameworks
|
|
96
|
+
if (allDeps.next) {
|
|
97
|
+
const isAppRouter = (await exists('app')) || (await exists('src/app'));
|
|
98
|
+
profile.frameworks.push(`Next.js (${isAppRouter ? 'App Router' : 'Pages Router'})`);
|
|
99
|
+
profile.recommendedSkills.push('nextjs');
|
|
100
|
+
}
|
|
101
|
+
if (allDeps.react) {
|
|
102
|
+
profile.frameworks.push('React');
|
|
103
|
+
profile.recommendedSkills.push('react');
|
|
104
|
+
}
|
|
105
|
+
if (allDeps.vue) {
|
|
106
|
+
profile.frameworks.push('Vue');
|
|
107
|
+
profile.recommendedSkills.push('vue');
|
|
108
|
+
}
|
|
109
|
+
if (allDeps.svelte) {
|
|
110
|
+
profile.frameworks.push('Svelte');
|
|
111
|
+
profile.recommendedSkills.push('svelte');
|
|
112
|
+
}
|
|
113
|
+
if (allDeps.astro) {
|
|
114
|
+
profile.frameworks.push('Astro');
|
|
115
|
+
profile.recommendedSkills.push('astro');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Styling
|
|
119
|
+
if (allDeps.tailwindcss || await exists('tailwind.config.js') || await exists('tailwind.config.ts')) {
|
|
120
|
+
profile.styling.push('TailwindCSS');
|
|
121
|
+
profile.recommendedSkills.push('tailwind');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Backend
|
|
125
|
+
if (allDeps.express) {
|
|
126
|
+
profile.backend.push('Express.js');
|
|
127
|
+
profile.recommendedSkills.push('express');
|
|
128
|
+
profile.recommendedSkills.push('api-architecture');
|
|
129
|
+
}
|
|
130
|
+
if (allDeps['@nestjs/core']) {
|
|
131
|
+
profile.backend.push('NestJS');
|
|
132
|
+
profile.recommendedSkills.push('nestjs');
|
|
133
|
+
}
|
|
134
|
+
if (allDeps.fastify) {
|
|
135
|
+
profile.backend.push('Fastify');
|
|
136
|
+
profile.recommendedSkills.push('fastify');
|
|
137
|
+
}
|
|
138
|
+
if (allDeps.hono) {
|
|
139
|
+
profile.backend.push('Hono');
|
|
140
|
+
}
|
|
141
|
+
if (allDeps['@trpc/server']) {
|
|
142
|
+
profile.backend.push('tRPC');
|
|
143
|
+
profile.recommendedSkills.push('trpc');
|
|
144
|
+
}
|
|
145
|
+
if (allDeps.graphql) {
|
|
146
|
+
profile.backend.push('GraphQL');
|
|
147
|
+
profile.recommendedSkills.push('graphql');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Database & ORMs
|
|
151
|
+
if (allDeps['@prisma/client'] || await exists('prisma/schema.prisma')) {
|
|
152
|
+
profile.database.push('Prisma ORM');
|
|
153
|
+
profile.recommendedSkills.push('prisma');
|
|
154
|
+
profile.recommendedSkills.push('query-optimization');
|
|
155
|
+
|
|
156
|
+
// Check DB provider in prisma schema
|
|
157
|
+
const schemaText = await readText('prisma/schema.prisma');
|
|
158
|
+
if (schemaText) {
|
|
159
|
+
if (schemaText.includes('provider = "postgresql"') || schemaText.includes('provider = "postgres"')) {
|
|
160
|
+
profile.database.push('PostgreSQL');
|
|
161
|
+
profile.recommendedSkills.push('postgresql');
|
|
162
|
+
} else if (schemaText.includes('provider = "mysql"')) {
|
|
163
|
+
profile.database.push('MySQL');
|
|
164
|
+
profile.recommendedSkills.push('mysql');
|
|
165
|
+
} else if (schemaText.includes('provider = "sqlite"')) {
|
|
166
|
+
profile.database.push('SQLite');
|
|
167
|
+
profile.recommendedSkills.push('sqlite');
|
|
168
|
+
} else if (schemaText.includes('provider = "mongodb"')) {
|
|
169
|
+
profile.database.push('MongoDB');
|
|
170
|
+
profile.recommendedSkills.push('mongodb');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (allDeps['drizzle-orm'] || await exists('drizzle.config.ts') || await exists('drizzle.config.js')) {
|
|
176
|
+
profile.database.push('Drizzle ORM');
|
|
177
|
+
profile.recommendedSkills.push('drizzle');
|
|
178
|
+
}
|
|
179
|
+
if (allDeps.typeorm) {
|
|
180
|
+
profile.database.push('TypeORM');
|
|
181
|
+
profile.recommendedSkills.push('typeorm');
|
|
182
|
+
}
|
|
183
|
+
if (allDeps.mongoose) {
|
|
184
|
+
profile.database.push('Mongoose (MongoDB)');
|
|
185
|
+
profile.recommendedSkills.push('mongodb');
|
|
186
|
+
}
|
|
187
|
+
if (allDeps.pg) {
|
|
188
|
+
if (!profile.database.includes('PostgreSQL')) profile.database.push('PostgreSQL');
|
|
189
|
+
profile.recommendedSkills.push('postgresql');
|
|
190
|
+
}
|
|
191
|
+
if (allDeps.redis || allDeps.ioredis || allDeps['@upstash/redis']) {
|
|
192
|
+
profile.database.push('Redis');
|
|
193
|
+
profile.recommendedSkills.push('redis-caching');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Testing
|
|
197
|
+
if (allDeps.vitest) {
|
|
198
|
+
profile.testing.push('Vitest');
|
|
199
|
+
profile.recommendedSkills.push('vitest');
|
|
200
|
+
}
|
|
201
|
+
if (allDeps.jest) {
|
|
202
|
+
profile.testing.push('Jest');
|
|
203
|
+
profile.recommendedSkills.push('jest');
|
|
204
|
+
}
|
|
205
|
+
if (allDeps['@playwright/test']) {
|
|
206
|
+
profile.testing.push('Playwright');
|
|
207
|
+
profile.recommendedSkills.push('playwright-e2e');
|
|
208
|
+
}
|
|
209
|
+
if (allDeps.cypress) {
|
|
210
|
+
profile.testing.push('Cypress');
|
|
211
|
+
profile.recommendedSkills.push('cypress-e2e');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Auth
|
|
215
|
+
if (allDeps['next-auth'] || allDeps['@auth/core']) {
|
|
216
|
+
profile.auth.push('NextAuth / Auth.js');
|
|
217
|
+
profile.recommendedSkills.push('auth-security');
|
|
218
|
+
}
|
|
219
|
+
if (allDeps['@clerk/nextjs'] || allDeps['@clerk/clerk-react']) {
|
|
220
|
+
profile.auth.push('Clerk Auth');
|
|
221
|
+
}
|
|
222
|
+
if (allDeps['@supabase/supabase-js'] || allDeps['@supabase/ssr']) {
|
|
223
|
+
profile.auth.push('Supabase Auth & DB');
|
|
224
|
+
profile.recommendedSkills.push('supabase');
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// 3. Python Ecosystem Detection
|
|
229
|
+
if (await exists('requirements.txt') || await exists('pyproject.toml') || await exists('Pipfile')) {
|
|
230
|
+
profile.languages.push('Python');
|
|
231
|
+
const reqText = (await readText('requirements.txt')) || (await readText('pyproject.toml')) || '';
|
|
232
|
+
if (reqText.includes('django')) {
|
|
233
|
+
profile.backend.push('Django');
|
|
234
|
+
profile.recommendedSkills.push('django');
|
|
235
|
+
}
|
|
236
|
+
if (reqText.includes('fastapi')) {
|
|
237
|
+
profile.backend.push('FastAPI');
|
|
238
|
+
profile.recommendedSkills.push('fastapi');
|
|
239
|
+
profile.recommendedSkills.push('api-architecture');
|
|
240
|
+
}
|
|
241
|
+
if (reqText.includes('sqlalchemy')) {
|
|
242
|
+
profile.database.push('SQLAlchemy');
|
|
243
|
+
profile.recommendedSkills.push('sqlalchemy');
|
|
244
|
+
}
|
|
245
|
+
if (reqText.includes('pytest')) {
|
|
246
|
+
profile.testing.push('Pytest');
|
|
247
|
+
profile.recommendedSkills.push('pytest');
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// 4. Go Ecosystem Detection
|
|
252
|
+
if (await exists('go.mod')) {
|
|
253
|
+
profile.languages.push('Go');
|
|
254
|
+
const goMod = await readText('go.mod');
|
|
255
|
+
if (goMod && goMod.includes('gin-gonic/gin')) profile.backend.push('Gin');
|
|
256
|
+
if (goMod && goMod.includes('gorm.io/gorm')) profile.database.push('GORM');
|
|
257
|
+
profile.recommendedSkills.push('go-architecture');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 5. Rust Ecosystem Detection
|
|
261
|
+
if (await exists('Cargo.toml')) {
|
|
262
|
+
profile.languages.push('Rust');
|
|
263
|
+
profile.recommendedSkills.push('rust-architecture');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Fallbacks if empty
|
|
267
|
+
if (profile.languages.length === 0) profile.languages.push('JavaScript');
|
|
268
|
+
if (profile.frameworks.length === 0) profile.frameworks.push('Standard Web / DOM');
|
|
269
|
+
if (profile.backend.length === 0) profile.backend.push('Node.js API');
|
|
270
|
+
if (profile.database.length === 0) profile.database.push('SQL / Relational DB');
|
|
271
|
+
if (profile.testing.length === 0) profile.testing.push('Unit & E2E Testing');
|
|
272
|
+
|
|
273
|
+
// Always include core skills
|
|
274
|
+
profile.recommendedSkills.push('codebase-intelligence', 'security-audit', 'performance-profiling', 'testing');
|
|
275
|
+
profile.recommendedSkills = [...new Set(profile.recommendedSkills)];
|
|
276
|
+
|
|
277
|
+
return profile;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Generates tailored agent configurations and skills mapped to the analyzed codebase
|
|
282
|
+
*/
|
|
283
|
+
export function buildAdaptedConfig(profile, options = {}) {
|
|
284
|
+
const isTypeScript = profile.languages.includes('TypeScript');
|
|
285
|
+
const hasPrisma = profile.database.includes('Prisma ORM');
|
|
286
|
+
const hasNext = profile.frameworks.some(f => f.includes('Next.js'));
|
|
287
|
+
|
|
288
|
+
// Detect directories present in project for permissions
|
|
289
|
+
const srcPrefix = profile.directories.includes('src') ? 'src/' : '';
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
version: "0.1.0",
|
|
293
|
+
project: profile.projectName,
|
|
294
|
+
codebaseProfile: {
|
|
295
|
+
languages: profile.languages,
|
|
296
|
+
frameworks: profile.frameworks,
|
|
297
|
+
backend: profile.backend,
|
|
298
|
+
database: profile.database,
|
|
299
|
+
testing: profile.testing,
|
|
300
|
+
auth: profile.auth,
|
|
301
|
+
styling: profile.styling
|
|
302
|
+
},
|
|
303
|
+
orchestrator: {
|
|
304
|
+
enabled: true,
|
|
305
|
+
maxConcurrentAgents: 4,
|
|
306
|
+
autoDecompose: true,
|
|
307
|
+
logEvents: true
|
|
308
|
+
},
|
|
309
|
+
agents: {
|
|
310
|
+
frontend: {
|
|
311
|
+
name: "Frontend Agent",
|
|
312
|
+
role: `${profile.frameworks[0] || 'UI/UX'} & Component Engineering`,
|
|
313
|
+
sprite: "frontend",
|
|
314
|
+
color: "#00f0ff",
|
|
315
|
+
enabled: true,
|
|
316
|
+
maxTasks: 2,
|
|
317
|
+
skills: profile.recommendedSkills.filter(s => ['react', 'nextjs', 'vue', 'svelte', 'astro', 'tailwind', 'ui-optimization'].includes(s)),
|
|
318
|
+
permissions: {
|
|
319
|
+
read: [`${srcPrefix}components/**`, `${srcPrefix}pages/**`, `${srcPrefix}app/**`, `${srcPrefix}styles/**`, "public/**"],
|
|
320
|
+
write: [`${srcPrefix}components/**`, `${srcPrefix}pages/**`, `${srcPrefix}app/**`, `${srcPrefix}styles/**`]
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
backend: {
|
|
324
|
+
name: "Backend Agent",
|
|
325
|
+
role: `${profile.backend[0] || 'API'} Architecture & Business Logic`,
|
|
326
|
+
sprite: "backend",
|
|
327
|
+
color: "#ff007f",
|
|
328
|
+
enabled: true,
|
|
329
|
+
maxTasks: 2,
|
|
330
|
+
skills: profile.recommendedSkills.filter(s => ['api-architecture', 'node', 'express', 'nestjs', 'fastify', 'trpc', 'graphql', 'fastapi', 'django', 'go-architecture', 'auth-security'].includes(s)),
|
|
331
|
+
permissions: {
|
|
332
|
+
read: [`${srcPrefix}api/**`, `${srcPrefix}server/**`, `${srcPrefix}routes/**`, `${srcPrefix}controllers/**`, `${srcPrefix}lib/**`],
|
|
333
|
+
write: [`${srcPrefix}api/**`, `${srcPrefix}server/**`, `${srcPrefix}routes/**`, `${srcPrefix}controllers/**`]
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
database: {
|
|
337
|
+
name: "Database Agent",
|
|
338
|
+
role: `${profile.database[0] || 'Database'} & Data Modeling Architect`,
|
|
339
|
+
sprite: "database",
|
|
340
|
+
color: "#ffd700",
|
|
341
|
+
enabled: true,
|
|
342
|
+
maxTasks: 1,
|
|
343
|
+
skills: profile.recommendedSkills.filter(s => ['postgresql', 'prisma', 'drizzle', 'typeorm', 'mongodb', 'mysql', 'sqlite', 'query-optimization', 'indexing', 'redis-caching'].includes(s)),
|
|
344
|
+
permissions: {
|
|
345
|
+
read: ["prisma/**", "db/**", "migrations/**", "models/**", "drizzle/**"],
|
|
346
|
+
write: ["prisma/**", "db/**", "migrations/**", "drizzle/**"]
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
security: {
|
|
350
|
+
name: "Security Agent",
|
|
351
|
+
role: "OWASP & Vulnerability Hardening",
|
|
352
|
+
sprite: "security",
|
|
353
|
+
color: "#ff3344",
|
|
354
|
+
enabled: true,
|
|
355
|
+
maxTasks: 1,
|
|
356
|
+
skills: ["security-audit", "codebase-intelligence", "auth-security"],
|
|
357
|
+
permissions: {
|
|
358
|
+
read: ["**/*"],
|
|
359
|
+
write: ["security/**", ".env.example"]
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
performance: {
|
|
363
|
+
name: "Performance Agent",
|
|
364
|
+
role: "Core Web Vitals & Runtime Profiling",
|
|
365
|
+
sprite: "performance",
|
|
366
|
+
color: "#39ff14",
|
|
367
|
+
enabled: true,
|
|
368
|
+
maxTasks: 1,
|
|
369
|
+
skills: ["performance-profiling", "lcp-optimization", "memory-profiling"],
|
|
370
|
+
permissions: {
|
|
371
|
+
read: ["**/*"],
|
|
372
|
+
write: [`${srcPrefix}**/*`]
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
qa: {
|
|
376
|
+
name: "QA Agent",
|
|
377
|
+
role: `${profile.testing[0] || 'Testing'} Automation Lead`,
|
|
378
|
+
sprite: "qa",
|
|
379
|
+
color: "#b026ff",
|
|
380
|
+
enabled: true,
|
|
381
|
+
maxTasks: 1,
|
|
382
|
+
dependsOn: ["frontend", "backend", "database"],
|
|
383
|
+
skills: profile.recommendedSkills.filter(s => ['testing', 'vitest', 'jest', 'playwright-e2e', 'cypress-e2e', 'pytest'].includes(s)),
|
|
384
|
+
permissions: {
|
|
385
|
+
read: ["**/*"],
|
|
386
|
+
write: ["tests/**", "__tests__/**", "cypress/**", "playwright/**", "e2e/**"]
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
dashboard: {
|
|
391
|
+
enabled: true,
|
|
392
|
+
port: 4747,
|
|
393
|
+
theme: "pixel",
|
|
394
|
+
crtEffect: true,
|
|
395
|
+
soundEffects: true
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import readline from 'node:readline/promises';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { DEFAULT_CONFIG, INITIAL_STATE, AGENT_MARKDOWNS, SKILL_MARKDOWNS } from './templates.js';
|
|
6
|
+
import { analyzeCodebase, buildAdaptedConfig } from './analyzer.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Initializes a new .pixel-agents workspace adapted to the target directory
|
|
10
|
+
*/
|
|
11
|
+
export async function initializeProject(targetDir = process.cwd(), options = {}) {
|
|
12
|
+
const isInteractive = !options.yes && process.stdin.isTTY;
|
|
13
|
+
let projectName = options.name || path.basename(targetDir);
|
|
14
|
+
let enableDashboard = true;
|
|
15
|
+
|
|
16
|
+
if (isInteractive) {
|
|
17
|
+
const rl = readline.createInterface({
|
|
18
|
+
input: process.stdin,
|
|
19
|
+
output: process.stdout
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
console.log('\n\x1b[36m' + `
|
|
23
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
24
|
+
║ PIXEL AGENTS - Multi-Agent Orchestration Framework ║
|
|
25
|
+
║ [ ◉ _ ◉ ] ║
|
|
26
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
27
|
+
` + '\x1b[0m');
|
|
28
|
+
|
|
29
|
+
const nameAns = await rl.question(`? Project name (${projectName}): `);
|
|
30
|
+
if (nameAns.trim()) {
|
|
31
|
+
projectName = nameAns.trim();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const dashAns = await rl.question(`? Enable visual pixel dashboard? (Y/n): `);
|
|
35
|
+
if (dashAns.trim().toLowerCase() === 'n') {
|
|
36
|
+
enableDashboard = false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
rl.close();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
console.log('\n\x1b[33mInitializing Pixel Agents in:\x1b[0m', targetDir);
|
|
43
|
+
|
|
44
|
+
// 1. Deep Codebase Analysis & Context Extraction
|
|
45
|
+
console.log('\x1b[36m🔍 Scanning and analyzing codebase architecture...\x1b[0m');
|
|
46
|
+
const profile = await analyzeCodebase(targetDir);
|
|
47
|
+
if (options.name) {
|
|
48
|
+
profile.projectName = options.name;
|
|
49
|
+
projectName = options.name;
|
|
50
|
+
} else if (profile.projectName) {
|
|
51
|
+
projectName = profile.projectName;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log(` \x1b[90m• Languages:\x1b[0m ${profile.languages.join(', ') || 'JavaScript'}`);
|
|
55
|
+
console.log(` \x1b[90m• Frameworks:\x1b[0m ${profile.frameworks.join(', ') || 'Standard Web'}`);
|
|
56
|
+
console.log(` \x1b[90m• Backend:\x1b[0m ${profile.backend.join(', ') || 'Node.js'}`);
|
|
57
|
+
console.log(` \x1b[90m• Database:\x1b[0m ${profile.database.join(', ') || 'SQL / Relational'}`);
|
|
58
|
+
console.log(` \x1b[90m• Testing:\x1b[0m ${profile.testing.join(', ') || 'Standard Testing'}`);
|
|
59
|
+
|
|
60
|
+
const pixelAgentsDir = path.join(targetDir, '.pixel-agents');
|
|
61
|
+
const agentsDir = path.join(pixelAgentsDir, 'agents');
|
|
62
|
+
const skillsDir = path.join(pixelAgentsDir, 'skills');
|
|
63
|
+
const dashboardDir = path.join(targetDir, '.pixel-dashboard');
|
|
64
|
+
|
|
65
|
+
// Create directories
|
|
66
|
+
await fs.mkdir(pixelAgentsDir, { recursive: true });
|
|
67
|
+
await fs.mkdir(agentsDir, { recursive: true });
|
|
68
|
+
await fs.mkdir(skillsDir, { recursive: true });
|
|
69
|
+
if (enableDashboard) {
|
|
70
|
+
await fs.mkdir(dashboardDir, { recursive: true });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 2. Build Context-Adapted Config
|
|
74
|
+
const adaptedConfig = buildAdaptedConfig(profile, options);
|
|
75
|
+
adaptedConfig.project = projectName;
|
|
76
|
+
adaptedConfig.dashboard.enabled = enableDashboard;
|
|
77
|
+
|
|
78
|
+
await fs.writeFile(
|
|
79
|
+
path.join(pixelAgentsDir, 'config.json'),
|
|
80
|
+
JSON.stringify(adaptedConfig, null, 2),
|
|
81
|
+
'utf-8'
|
|
82
|
+
);
|
|
83
|
+
console.log(' \x1b[32m✓\x1b[0m Created .pixel-agents/config.json (tailored agent roles & permissions)');
|
|
84
|
+
|
|
85
|
+
// 3. Write Codebase Context Cache
|
|
86
|
+
await fs.writeFile(
|
|
87
|
+
path.join(pixelAgentsDir, 'context.json'),
|
|
88
|
+
JSON.stringify(profile, null, 2),
|
|
89
|
+
'utf-8'
|
|
90
|
+
);
|
|
91
|
+
console.log(' \x1b[32m✓\x1b[0m Created .pixel-agents/context.json (grounded codebase context)');
|
|
92
|
+
|
|
93
|
+
// 4. Write state.json
|
|
94
|
+
const state = JSON.parse(JSON.stringify(INITIAL_STATE));
|
|
95
|
+
state.startedAt = new Date().toISOString();
|
|
96
|
+
await fs.writeFile(
|
|
97
|
+
path.join(pixelAgentsDir, 'state.json'),
|
|
98
|
+
JSON.stringify(state, null, 2),
|
|
99
|
+
'utf-8'
|
|
100
|
+
);
|
|
101
|
+
console.log(' \x1b[32m✓\x1b[0m Created .pixel-agents/state.json');
|
|
102
|
+
|
|
103
|
+
// 5. Write initial events.jsonl
|
|
104
|
+
const initialEvent = {
|
|
105
|
+
id: 'evt-0',
|
|
106
|
+
timestamp: Date.now(),
|
|
107
|
+
agent: 'orchestrator',
|
|
108
|
+
type: 'spawn',
|
|
109
|
+
message: `Pixel Agents swarm initialized & adapted to ${profile.frameworks.join(', ') || 'codebase'}`,
|
|
110
|
+
metadata: { version: '0.1.0', profile }
|
|
111
|
+
};
|
|
112
|
+
await fs.writeFile(
|
|
113
|
+
path.join(pixelAgentsDir, 'events.jsonl'),
|
|
114
|
+
JSON.stringify(initialEvent) + '\n',
|
|
115
|
+
'utf-8'
|
|
116
|
+
);
|
|
117
|
+
console.log(' \x1b[32m✓\x1b[0m Created .pixel-agents/events.jsonl');
|
|
118
|
+
|
|
119
|
+
// 6. Write agents/*.md
|
|
120
|
+
for (const [filename, content] of Object.entries(AGENT_MARKDOWNS)) {
|
|
121
|
+
await fs.writeFile(path.join(agentsDir, filename), content.trim() + '\n', 'utf-8');
|
|
122
|
+
}
|
|
123
|
+
console.log(` \x1b[32m✓\x1b[0m Created ${Object.keys(AGENT_MARKDOWNS).length} agent definitions in .pixel-agents/agents/`);
|
|
124
|
+
|
|
125
|
+
// 7. Write skills/*.md
|
|
126
|
+
for (const [filename, content] of Object.entries(SKILL_MARKDOWNS)) {
|
|
127
|
+
await fs.writeFile(path.join(skillsDir, filename), content.trim() + '\n', 'utf-8');
|
|
128
|
+
}
|
|
129
|
+
console.log(` \x1b[32m✓\x1b[0m Created ${Object.keys(SKILL_MARKDOWNS).length} skill definitions in .pixel-agents/skills/`);
|
|
130
|
+
|
|
131
|
+
// 8. Copy dashboard static files if enabled
|
|
132
|
+
if (enableDashboard) {
|
|
133
|
+
const srcDashboardDir = fileURLToPath(new URL('../dashboard', import.meta.url));
|
|
134
|
+
try {
|
|
135
|
+
const html = await fs.readFile(path.join(srcDashboardDir, 'index.html'), 'utf-8');
|
|
136
|
+
const css = await fs.readFile(path.join(srcDashboardDir, 'styles.css'), 'utf-8');
|
|
137
|
+
const js = await fs.readFile(path.join(srcDashboardDir, 'app.js'), 'utf-8');
|
|
138
|
+
|
|
139
|
+
await fs.writeFile(path.join(dashboardDir, 'index.html'), html, 'utf-8');
|
|
140
|
+
await fs.writeFile(path.join(dashboardDir, 'styles.css'), css, 'utf-8');
|
|
141
|
+
await fs.writeFile(path.join(dashboardDir, 'app.js'), js, 'utf-8');
|
|
142
|
+
console.log(' \x1b[32m✓\x1b[0m Created .pixel-dashboard/ (index.html, styles.css, app.js)');
|
|
143
|
+
} catch (err) {
|
|
144
|
+
// ignore
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
console.log('\n\x1b[32m\x1b[1mPixel Agents initialized & adapted successfully!\x1b[0m\n');
|
|
149
|
+
console.log('Next steps:');
|
|
150
|
+
console.log(' \x1b[36mnpx pixel-agents start\x1b[0m Launch orchestration server & dashboard');
|
|
151
|
+
console.log(' \x1b[36mnpx pixel-agents demo\x1b[0m Run an interactive multi-agent demo');
|
|
152
|
+
console.log(' \x1b[36mnpx pixel-agents task "..."\x1b[0m Dispatch a task to the agent swarm\n');
|
|
153
|
+
|
|
154
|
+
return { pixelAgentsDir, dashboardDir, profile };
|
|
155
|
+
}
|