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,372 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'node:fs/promises';
|
|
5
|
+
import fsSync from 'node:fs';
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { initializeProject } from '../src/scaffold/init.js';
|
|
8
|
+
import { OrchestratorEngine } from '../src/orchestrator/engine.js';
|
|
9
|
+
import { createServer } from '../src/server/server.js';
|
|
10
|
+
|
|
11
|
+
const BANNER = `\x1b[36m
|
|
12
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
13
|
+
║ PIXEL AGENTS - Multi-Agent Orchestration Framework ║
|
|
14
|
+
║ [ ◉ _ ◉ ] ║
|
|
15
|
+
╚═══════════════════════════════════════════════════════════╝\x1b[0m`;
|
|
16
|
+
|
|
17
|
+
function printHelp() {
|
|
18
|
+
console.log(BANNER);
|
|
19
|
+
console.log(`
|
|
20
|
+
\x1b[1mUSAGE:\x1b[0m
|
|
21
|
+
npx pixel-agents <command> [options]
|
|
22
|
+
|
|
23
|
+
\x1b[1mCOMMANDS:\x1b[0m
|
|
24
|
+
\x1b[32minit\x1b[0m Initialize .pixel-agents/ workspace in current project
|
|
25
|
+
\x1b[32manalyze\x1b[0m Inspect and display detected frameworks, ORMs, and architecture
|
|
26
|
+
\x1b[32mstart\x1b[0m Start multi-agent orchestrator & live pixel dashboard
|
|
27
|
+
\x1b[32mdashboard\x1b[0m Launch the visual pixel dashboard UI
|
|
28
|
+
\x1b[32mdemo\x1b[0m Launch server and run an interactive multi-agent demo
|
|
29
|
+
\x1b[32mtask\x1b[0m "<description>" Dispatch an objective to the agent swarm
|
|
30
|
+
\x1b[32memit\x1b[0m [options] Emit an event to the stream (e.g. from external hooks)
|
|
31
|
+
\x1b[32mstatus\x1b[0m Display active swarm state and agent roster
|
|
32
|
+
\x1b[32mhelp\x1b[0m Show this help reference
|
|
33
|
+
|
|
34
|
+
\x1b[1mOPTIONS:\x1b[0m
|
|
35
|
+
--port <number> Set dashboard port (default: 4747)
|
|
36
|
+
--no-open Do not automatically open the browser
|
|
37
|
+
--yes, -y Skip prompts and use defaults during init
|
|
38
|
+
--name <name> Set project name during init
|
|
39
|
+
--agent <name> Specify agent for emit (e.g. frontend, backend, qa)
|
|
40
|
+
--type <type> Event type for emit (spawn, thinking, tool, skill, complete, error)
|
|
41
|
+
--message <msg> Event message for emit
|
|
42
|
+
--skill <skill> Associated skill for emit
|
|
43
|
+
|
|
44
|
+
\x1b[1mEXAMPLES:\x1b[0m
|
|
45
|
+
npx pixel-agents init
|
|
46
|
+
npx pixel-agents start
|
|
47
|
+
npx pixel-agents demo
|
|
48
|
+
npx pixel-agents task "Find slow Prisma queries and optimize indexes"
|
|
49
|
+
npx pixel-agents emit --agent database --type tool --skill prisma --message "Analyzing queries"
|
|
50
|
+
`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function openBrowser(url) {
|
|
54
|
+
const platform = process.platform;
|
|
55
|
+
let cmd = 'open';
|
|
56
|
+
if (platform === 'win32') cmd = 'start';
|
|
57
|
+
else if (platform === 'linux') cmd = 'xdg-open';
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
spawn(cmd, [url], { detached: true, stdio: 'ignore' }).unref();
|
|
61
|
+
} catch (err) {
|
|
62
|
+
// Ignore browser open errors
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function resolveDaemonUrl(rootDir) {
|
|
67
|
+
// 1. Check .pixel-agents/daemon.json
|
|
68
|
+
const daemonPath = path.join(rootDir, '.pixel-agents', 'daemon.json');
|
|
69
|
+
try {
|
|
70
|
+
const raw = await fs.readFile(daemonPath, 'utf-8');
|
|
71
|
+
const info = JSON.parse(raw);
|
|
72
|
+
if (info?.url) {
|
|
73
|
+
const res = await fetch(`${info.url}/api/info`, { signal: AbortSignal.timeout(600) });
|
|
74
|
+
if (res.ok) {
|
|
75
|
+
const serverInfo = await res.json();
|
|
76
|
+
if (!serverInfo.rootDir || serverInfo.rootDir === rootDir) {
|
|
77
|
+
return info.url;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
} catch {}
|
|
82
|
+
|
|
83
|
+
// 2. Scan fallback ports 4747..4755 and verify rootDir
|
|
84
|
+
for (let port = 4747; port <= 4755; port++) {
|
|
85
|
+
try {
|
|
86
|
+
const res = await fetch(`http://localhost:${port}/api/info`, { signal: AbortSignal.timeout(300) });
|
|
87
|
+
if (res.ok) {
|
|
88
|
+
const serverInfo = await res.json();
|
|
89
|
+
if (serverInfo.rootDir && serverInfo.rootDir === rootDir) {
|
|
90
|
+
return `http://localhost:${port}`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} catch {}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function startServerWithPortFallback(server, initialPort, maxTries = 20) {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
let currentPort = initialPort;
|
|
102
|
+
let attempts = 0;
|
|
103
|
+
|
|
104
|
+
function tryListen() {
|
|
105
|
+
server.removeAllListeners('error');
|
|
106
|
+
server.removeAllListeners('listening');
|
|
107
|
+
|
|
108
|
+
server.once('error', (err) => {
|
|
109
|
+
if (err.code === 'EADDRINUSE') {
|
|
110
|
+
attempts++;
|
|
111
|
+
if (attempts >= maxTries) {
|
|
112
|
+
reject(new Error(`Could not find an available port after ${maxTries} attempts (starting at port ${initialPort}).`));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
currentPort++;
|
|
116
|
+
console.log(`\x1b[33mPort ${currentPort - 1} is already in use. Trying next port ${currentPort}...\x1b[0m`);
|
|
117
|
+
tryListen();
|
|
118
|
+
} else {
|
|
119
|
+
reject(err);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
server.once('listening', () => {
|
|
124
|
+
resolve(currentPort);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
server.listen(currentPort);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
tryListen();
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function main() {
|
|
135
|
+
const args = process.argv.slice(2);
|
|
136
|
+
const command = args[0] || 'help';
|
|
137
|
+
|
|
138
|
+
// Parse arguments
|
|
139
|
+
const options = {};
|
|
140
|
+
for (let i = 1; i < args.length; i++) {
|
|
141
|
+
if (args[i] === '--yes' || args[i] === '-y') options.yes = true;
|
|
142
|
+
else if (args[i] === '--no-open') options.noOpen = true;
|
|
143
|
+
else if (args[i] === '--port' && args[i + 1]) options.port = parseInt(args[++i], 10);
|
|
144
|
+
else if (args[i] === '--name' && args[i + 1]) options.name = args[++i];
|
|
145
|
+
else if (args[i] === '--agent' && args[i + 1]) options.agent = args[++i];
|
|
146
|
+
else if (args[i] === '--type' && args[i + 1]) options.type = args[++i];
|
|
147
|
+
else if (args[i] === '--message' && args[i + 1]) options.message = args[++i];
|
|
148
|
+
else if (args[i] === '--skill' && args[i + 1]) options.skill = args[++i];
|
|
149
|
+
else if (!args[i].startsWith('-') && !options.taskPrompt) {
|
|
150
|
+
options.taskPrompt = args[i];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const rootDir = process.cwd();
|
|
155
|
+
|
|
156
|
+
switch (command) {
|
|
157
|
+
case 'init': {
|
|
158
|
+
await initializeProject(rootDir, options);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
case 'analyze': {
|
|
163
|
+
console.log(BANNER);
|
|
164
|
+
console.log('\n\x1b[36m🔍 Analyzing Codebase Architecture & Context...\x1b[0m\n');
|
|
165
|
+
const { analyzeCodebase } = await import('../src/scaffold/analyzer.js');
|
|
166
|
+
const profile = await analyzeCodebase(rootDir);
|
|
167
|
+
|
|
168
|
+
console.log(`\x1b[1mPROJECT:\x1b[0m ${profile.projectName}`);
|
|
169
|
+
console.log(`\x1b[1mLANGUAGES:\x1b[0m ${profile.languages.join(', ') || 'None'}`);
|
|
170
|
+
console.log(`\x1b[1mFRAMEWORKS:\x1b[0m ${profile.frameworks.join(', ') || 'None'}`);
|
|
171
|
+
console.log(`\x1b[1mBACKEND / API:\x1b[0m ${profile.backend.join(', ') || 'None'}`);
|
|
172
|
+
console.log(`\x1b[1mDATABASE / ORM:\x1b[0m ${profile.database.join(', ') || 'None'}`);
|
|
173
|
+
console.log(`\x1b[1mTESTING SUITE:\x1b[0m ${profile.testing.join(', ') || 'None'}`);
|
|
174
|
+
console.log(`\x1b[1mAUTH / SECURITY:\x1b[0m ${profile.auth.join(', ') || 'None'}`);
|
|
175
|
+
console.log(`\x1b[1mSTYLING SYSTEM:\x1b[0m ${profile.styling.join(', ') || 'None'}`);
|
|
176
|
+
console.log(`\x1b[1mRECOMMENDED SKILLS:\x1b[0m ${profile.recommendedSkills.join(', ')}\n`);
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
case 'start':
|
|
181
|
+
case 'dev':
|
|
182
|
+
case 'dashboard':
|
|
183
|
+
case 'demo': {
|
|
184
|
+
// Check if project is initialized
|
|
185
|
+
const configPath = path.join(rootDir, '.pixel-agents', 'config.json');
|
|
186
|
+
try {
|
|
187
|
+
await fs.access(configPath);
|
|
188
|
+
} catch {
|
|
189
|
+
console.log('\x1b[33mProject not initialized yet. Running automatic init...\x1b[0m');
|
|
190
|
+
await initializeProject(rootDir, { yes: true });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const engine = new OrchestratorEngine(rootDir);
|
|
194
|
+
await engine.initialize();
|
|
195
|
+
|
|
196
|
+
const requestedPort = options.port || engine.getConfig()?.dashboard?.port || 4747;
|
|
197
|
+
const server = createServer(engine, options);
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
const boundPort = await startServerWithPortFallback(server, requestedPort);
|
|
201
|
+
const url = `http://localhost:${boundPort}`;
|
|
202
|
+
|
|
203
|
+
// Persist daemon discovery file
|
|
204
|
+
const daemonPath = path.join(rootDir, '.pixel-agents', 'daemon.json');
|
|
205
|
+
try {
|
|
206
|
+
await fs.writeFile(daemonPath, JSON.stringify({
|
|
207
|
+
port: boundPort,
|
|
208
|
+
pid: process.pid,
|
|
209
|
+
url,
|
|
210
|
+
startedAt: new Date().toISOString()
|
|
211
|
+
}, null, 2), 'utf-8');
|
|
212
|
+
} catch {}
|
|
213
|
+
|
|
214
|
+
const cleanupDaemon = () => {
|
|
215
|
+
try { fsSync.unlinkSync(daemonPath); } catch {}
|
|
216
|
+
};
|
|
217
|
+
process.on('exit', cleanupDaemon);
|
|
218
|
+
process.on('SIGINT', () => { cleanupDaemon(); process.exit(0); });
|
|
219
|
+
process.on('SIGTERM', () => { cleanupDaemon(); process.exit(0); });
|
|
220
|
+
|
|
221
|
+
console.log(BANNER);
|
|
222
|
+
console.log(`\n\x1b[32m\x1b[1m● PixelCrew Swarm Server Active\x1b[0m`);
|
|
223
|
+
console.log(` Visual Dashboard: \x1b[36m\x1b[4m${url}\x1b[0m`);
|
|
224
|
+
console.log(` Event Stream: \x1b[36m${url}/api/events\x1b[0m\n`);
|
|
225
|
+
console.log('\x1b[90mPress Ctrl+C to stop.\x1b[0m\n');
|
|
226
|
+
|
|
227
|
+
if (!options.noOpen) {
|
|
228
|
+
openBrowser(url);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Auto trigger demo if command was 'demo'
|
|
232
|
+
if (command === 'demo') {
|
|
233
|
+
setTimeout(() => {
|
|
234
|
+
const prompt = `Optimize ${engine.getConfig()?.project || 'app'} APIs, database queries & deploy responsive dashboard`;
|
|
235
|
+
console.log(`\x1b[33m[DEMO]\x1b[0m Dispatching swarm mission: "${prompt}"\n`);
|
|
236
|
+
engine.submitTask(prompt).catch(console.error);
|
|
237
|
+
}, 1200);
|
|
238
|
+
}
|
|
239
|
+
} catch (err) {
|
|
240
|
+
console.error(`\x1b[31mFailed to start server:\x1b[0m`, err.message);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Stream terminal events as they happen
|
|
245
|
+
engine.on('agent_event', (event) => {
|
|
246
|
+
const time = new Date(event.timestamp).toTimeString().split(' ')[0];
|
|
247
|
+
const agentPadded = (event.agent || 'orchestrator').padEnd(12);
|
|
248
|
+
let color = '\x1b[37m';
|
|
249
|
+
if (event.agent === 'orchestrator') color = '\x1b[33m';
|
|
250
|
+
else if (event.agent === 'frontend') color = '\x1b[36m';
|
|
251
|
+
else if (event.agent === 'backend') color = '\x1b[35m';
|
|
252
|
+
else if (event.agent === 'database') color = '\x1b[33m';
|
|
253
|
+
else if (event.agent === 'security') color = '\x1b[31m';
|
|
254
|
+
else if (event.agent === 'performance') color = '\x1b[32m';
|
|
255
|
+
else if (event.agent === 'qa') color = '\x1b[35m';
|
|
256
|
+
|
|
257
|
+
console.log(`\x1b[90m${time}\x1b[0m ${color}${agentPadded}\x1b[0m → ${event.message}`);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
case 'task': {
|
|
264
|
+
const taskPrompt = options.taskPrompt || args[1];
|
|
265
|
+
if (!taskPrompt) {
|
|
266
|
+
console.error('\x1b[31mError: Please provide a task description.\x1b[0m');
|
|
267
|
+
console.log('Example: npx pixel-agents task "Optimize Postgres queries"');
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Check if daemon server is running
|
|
272
|
+
const daemonUrl = await resolveDaemonUrl(rootDir);
|
|
273
|
+
if (daemonUrl) {
|
|
274
|
+
try {
|
|
275
|
+
const res = await fetch(`${daemonUrl}/api/task`, {
|
|
276
|
+
method: 'POST',
|
|
277
|
+
headers: { 'Content-Type': 'application/json' },
|
|
278
|
+
body: JSON.stringify({ prompt: taskPrompt })
|
|
279
|
+
});
|
|
280
|
+
if (res.ok) {
|
|
281
|
+
console.log(`\x1b[32m✓ Task dispatched to running swarm daemon (${daemonUrl}):\x1b[0m "${taskPrompt}"`);
|
|
282
|
+
console.log(`Check live status at ${daemonUrl}`);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
} catch {}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
console.log(BANNER);
|
|
289
|
+
console.log(`\x1b[33m[SWARM RUNNER]\x1b[0m Dispatching task: "${taskPrompt}"\n`);
|
|
290
|
+
const engine = new OrchestratorEngine(rootDir);
|
|
291
|
+
await engine.initialize();
|
|
292
|
+
|
|
293
|
+
engine.on('agent_event', (event) => {
|
|
294
|
+
const time = new Date(event.timestamp).toTimeString().split(' ')[0];
|
|
295
|
+
const agentPadded = (event.agent || 'orchestrator').padEnd(12);
|
|
296
|
+
console.log(`\x1b[90m${time}\x1b[0m \x1b[36m${agentPadded}\x1b[0m → ${event.message}`);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
const report = await engine.submitTask(taskPrompt);
|
|
300
|
+
if (report) {
|
|
301
|
+
console.log('\n\x1b[36m' + report + '\x1b[0m\n');
|
|
302
|
+
}
|
|
303
|
+
console.log('\x1b[32m✓ Sprint audit completed successfully.\x1b[0m\n');
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
case 'emit': {
|
|
308
|
+
const eventData = {
|
|
309
|
+
agent: options.agent || 'orchestrator',
|
|
310
|
+
type: options.type || 'progress',
|
|
311
|
+
message: options.message || 'Manual event trigger',
|
|
312
|
+
skill: options.skill
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const daemonUrl = await resolveDaemonUrl(rootDir);
|
|
316
|
+
if (daemonUrl) {
|
|
317
|
+
try {
|
|
318
|
+
const res = await fetch(`${daemonUrl}/api/emit`, {
|
|
319
|
+
method: 'POST',
|
|
320
|
+
headers: { 'Content-Type': 'application/json' },
|
|
321
|
+
body: JSON.stringify(eventData)
|
|
322
|
+
});
|
|
323
|
+
if (res.ok) {
|
|
324
|
+
console.log(`\x1b[32m✓ Event emitted to live dashboard (${daemonUrl}):\x1b[0m ${eventData.agent} → ${eventData.message}`);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
} catch {}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Local append & persist
|
|
331
|
+
const engine = new OrchestratorEngine(rootDir);
|
|
332
|
+
await engine.initialize();
|
|
333
|
+
await engine.emitEvent(eventData);
|
|
334
|
+
console.log(`\x1b[32m✓ Event recorded to .pixel-agents/events.jsonl:\x1b[0m ${eventData.agent} → ${eventData.message}`);
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
case 'status': {
|
|
339
|
+
const engine = new OrchestratorEngine(rootDir);
|
|
340
|
+
await engine.initialize();
|
|
341
|
+
const state = engine.getState();
|
|
342
|
+
const config = engine.getConfig();
|
|
343
|
+
|
|
344
|
+
console.log(BANNER);
|
|
345
|
+
console.log(`\n\x1b[1mPROJECT:\x1b[0m ${config?.project || 'my-app'}`);
|
|
346
|
+
console.log(`\x1b[1mSTATUS:\x1b[0m ${state.status === 'RUNNING' ? '\x1b[32m● RUNNING\x1b[0m' : '\x1b[33mSTANDBY\x1b[0m'}`);
|
|
347
|
+
console.log(`\x1b[1mTASK:\x1b[0m ${state.activeTask || 'None'}\n`);
|
|
348
|
+
console.log('\x1b[1mAGENT SWARM ROSTER:\x1b[0m');
|
|
349
|
+
console.log('─────────────────────────────────────────────────────────────');
|
|
350
|
+
for (const [key, agent] of Object.entries(config?.agents || {})) {
|
|
351
|
+
const aState = state.agents?.[key] || {};
|
|
352
|
+
const stateColor = aState.state === 'WORKING' ? '\x1b[35m' : (aState.state === 'COMPLETED' ? '\x1b[32m' : '\x1b[90m');
|
|
353
|
+
console.log(` ${key.padEnd(14)} [${stateColor}${(aState.state || 'IDLE').padEnd(10)}\x1b[0m] ${aState.expression || '●_●'} ${aState.currentTask || 'Idle'}`);
|
|
354
|
+
}
|
|
355
|
+
console.log('─────────────────────────────────────────────────────────────\n');
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
case 'help':
|
|
360
|
+
case '--help':
|
|
361
|
+
case '-h':
|
|
362
|
+
default: {
|
|
363
|
+
printHelp();
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
main().catch((err) => {
|
|
370
|
+
console.error('\x1b[31mFatal error:\x1b[0m', err);
|
|
371
|
+
process.exit(1);
|
|
372
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pixelcrew",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local multi-agent orchestration framework with an interactive pixel-art tech startup office visual dashboard",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"pixelcrew": "bin/pixel-agents.js",
|
|
9
|
+
"pixel-crew": "bin/pixel-agents.js",
|
|
10
|
+
"pixel-agents": "bin/pixel-agents.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/",
|
|
14
|
+
"src/",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"start": "node bin/pixel-agents.js start",
|
|
20
|
+
"init": "node bin/pixel-agents.js init",
|
|
21
|
+
"dashboard": "node bin/pixel-agents.js dashboard",
|
|
22
|
+
"demo": "node bin/pixel-agents.js demo",
|
|
23
|
+
"test": "node --test tests/**/*.test.js"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"agents",
|
|
27
|
+
"multi-agent",
|
|
28
|
+
"orchestrator",
|
|
29
|
+
"pixel-art",
|
|
30
|
+
"dashboard",
|
|
31
|
+
"llm",
|
|
32
|
+
"ai",
|
|
33
|
+
"workflow",
|
|
34
|
+
"terminal",
|
|
35
|
+
"startup-office",
|
|
36
|
+
"npx"
|
|
37
|
+
],
|
|
38
|
+
"author": "Arnel (@hiroqt)",
|
|
39
|
+
"license": "Apache-2.0",
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18.0.0"
|
|
42
|
+
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/hiroqt/PixelCrew.git"
|
|
46
|
+
}
|
|
47
|
+
}
|