@leejungkiin/awkit 1.1.7 โ†’ 1.2.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.
Files changed (48) hide show
  1. package/README.md +36 -4
  2. package/bin/awk.js +2 -2
  3. package/package.json +6 -3
  4. package/skill-packs/neural-memory/skills/nm-memory-sync/SKILL.md +14 -1
  5. package/skills/gitnexus-intelligence/SKILL.md +224 -0
  6. package/skills/orchestrator/SKILL.md +9 -0
  7. package/skills/symphony-orchestrator/SKILL.md +9 -7
  8. package/workflows/gitnexus.md +123 -0
  9. package/symphony/LICENSE +0 -21
  10. package/symphony/README.md +0 -178
  11. package/symphony/app/api/agents/route.js +0 -152
  12. package/symphony/app/api/events/route.js +0 -22
  13. package/symphony/app/api/knowledge/route.js +0 -253
  14. package/symphony/app/api/locks/route.js +0 -29
  15. package/symphony/app/api/notes/route.js +0 -125
  16. package/symphony/app/api/preflight/route.js +0 -23
  17. package/symphony/app/api/projects/route.js +0 -116
  18. package/symphony/app/api/roles/route.js +0 -134
  19. package/symphony/app/api/skills/route.js +0 -82
  20. package/symphony/app/api/status/route.js +0 -18
  21. package/symphony/app/api/tasks/route.js +0 -157
  22. package/symphony/app/api/workflows/route.js +0 -61
  23. package/symphony/app/api/workspaces/route.js +0 -15
  24. package/symphony/app/globals.css +0 -2605
  25. package/symphony/app/layout.js +0 -20
  26. package/symphony/app/page.js +0 -2122
  27. package/symphony/cli/index.js +0 -1060
  28. package/symphony/core/agent-manager.js +0 -357
  29. package/symphony/core/context-bus.js +0 -100
  30. package/symphony/core/db.js +0 -223
  31. package/symphony/core/file-lock-manager.js +0 -154
  32. package/symphony/core/merge-pipeline.js +0 -234
  33. package/symphony/core/orchestrator.js +0 -236
  34. package/symphony/core/task-manager.js +0 -335
  35. package/symphony/core/workspace-manager.js +0 -168
  36. package/symphony/jsconfig.json +0 -7
  37. package/symphony/lib/core.mjs +0 -1034
  38. package/symphony/mcp/index.js +0 -29
  39. package/symphony/mcp/server.js +0 -110
  40. package/symphony/mcp/tools/context.js +0 -80
  41. package/symphony/mcp/tools/locks.js +0 -99
  42. package/symphony/mcp/tools/status.js +0 -82
  43. package/symphony/mcp/tools/tasks.js +0 -216
  44. package/symphony/mcp/tools/workspace.js +0 -143
  45. package/symphony/next.config.mjs +0 -7
  46. package/symphony/package.json +0 -53
  47. package/symphony/scripts/postinstall.js +0 -49
  48. package/symphony/symphony.config.js +0 -41
@@ -1,1060 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Symphony CLI
5
- * Command-line interface for AWKit Symphony orchestration platform.
6
- */
7
- const { Command } = require('commander');
8
- const path = require('path');
9
-
10
- // Ensure core modules resolve relative to this file
11
- const SYMPHONY_ROOT = path.join(__dirname, '..');
12
- process.env.SYMPHONY_ROOT = SYMPHONY_ROOT;
13
-
14
- const program = new Command();
15
-
16
- program
17
- .name('symphony')
18
- .description('๐ŸŽผ AWKit Symphony โ€” Multi-Agent Orchestration')
19
- .version('0.1.0');
20
-
21
- // โ”€โ”€โ”€ Task Commands โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
22
-
23
- const taskCmd = program.command('task').description('Task management');
24
-
25
- taskCmd
26
- .command('list')
27
- .description('List tasks')
28
- .option('-s, --status <status>', 'Filter by status (ready|claimed|in_progress|review|done)')
29
- .option('-P, --project <id>', 'Filter by project ID')
30
- .option('-l, --limit <n>', 'Limit results', '20')
31
- .action((opts) => {
32
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
33
- const tasks = tm.listTasks({
34
- status: opts.status || undefined,
35
- project: opts.project || undefined,
36
- limit: parseInt(opts.limit),
37
- });
38
-
39
- if (tasks.length === 0) {
40
- console.log('No tasks found.');
41
- return;
42
- }
43
-
44
- const statusIcon = {
45
- ready: 'โฌœ', claimed: '๐ŸŸก', in_progress: '๐Ÿ”ต',
46
- review: '๐ŸŸฃ', done: 'โœ…', abandoned: 'โšซ',
47
- };
48
-
49
- console.log(`\n${'ID'.padEnd(14)} ${'Status'.padEnd(14)} ${'Pri'.padEnd(6)} ${'Project'.padEnd(12)} Title`);
50
- console.log('โ”€'.repeat(80));
51
- for (const t of tasks) {
52
- const icon = statusIcon[t.status] || 'โ“';
53
- const proj = (t.project_id || '-').substring(0, 10).padEnd(12);
54
- const pri = (typeof t.priority === 'number' ? `P${t.priority}` : (t.priority || '-')).padEnd(6);
55
- console.log(
56
- `${t.id.padEnd(14)} ${(icon + ' ' + t.status).padEnd(14)} ${pri} ${proj} ${t.title}`
57
- );
58
- }
59
- console.log(`\nTotal: ${tasks.length} task(s)\n`);
60
- closeDb();
61
- });
62
-
63
- taskCmd
64
- .command('create <title>')
65
- .description('Create a new task')
66
- .option('-p, --priority <n>', 'Priority (1=high, 3=low)', '2')
67
- .option('-d, --description <text>', 'Task description')
68
- .option('-a, --acceptance <text>', 'Acceptance criteria')
69
- .option('-P, --project <id>', 'Project ID')
70
- .option('--phase <phase>', 'Phase/group')
71
- .option('--skills <list>', 'Required skills (comma-separated, e.g. "code,debug")')
72
- .action((title, opts) => {
73
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
74
- const taskOpts = {
75
- priority: parseInt(opts.priority),
76
- description: opts.description,
77
- acceptance: opts.acceptance,
78
- phase: opts.phase,
79
- projectId: opts.project,
80
- };
81
- if (opts.skills) {
82
- taskOpts.requiredSkills = opts.skills.split(',').map(s => s.trim());
83
- }
84
- const task = tm.createTask(title, taskOpts);
85
- console.log(`\nโœ… Task created: ${task.id}`);
86
- console.log(` Title: ${task.title}`);
87
- console.log(` Priority: P${task.priority}`);
88
- console.log(` Project: ${task.project_id || '(none)'}`);
89
- if (opts.skills) console.log(` Skills: ${opts.skills}`);
90
- console.log(` Status: ${task.status}\n`);
91
- closeDb();
92
- });
93
-
94
- taskCmd
95
- .command('show <id>')
96
- .description('Show task details')
97
- .action((id) => {
98
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
99
- const task = tm.getTask(id);
100
- if (!task) {
101
- console.log(`โŒ Task not found: ${id}`);
102
- closeDb();
103
- return;
104
- }
105
- console.log(`\n๐ŸŽซ Task: ${task.id}`);
106
- console.log(` Title: ${task.title}`);
107
- console.log(` Status: ${task.status}`);
108
- console.log(` Priority: P${task.priority}`);
109
- console.log(` Agent: ${task.agent_id || '(unassigned)'}`);
110
- console.log(` Progress: ${task.progress}%`);
111
- if (task.description) console.log(` Description: ${task.description}`);
112
- if (task.acceptance) console.log(` Acceptance: ${task.acceptance}`);
113
- if (task.phase) console.log(` Phase: ${task.phase}`);
114
- if (task.branch) console.log(` Branch: ${task.branch}`);
115
- console.log(` Created: ${task.created_at}`);
116
- if (task.claimed_at) console.log(` Claimed: ${task.claimed_at}`);
117
- if (task.completed_at) console.log(` Completed: ${task.completed_at}`);
118
- if (task.summary) console.log(` Summary: ${task.summary}`);
119
- console.log('');
120
- closeDb();
121
- });
122
-
123
- taskCmd
124
- .command('claim <id>')
125
- .description('Claim a task (ready โ†’ claimed)')
126
- .option('-a, --agent <agent>', 'Agent ID', 'cli-user')
127
- .action((id, opts) => {
128
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
129
- try {
130
- const task = tm.claimTask(id, opts.agent);
131
- console.log(`\n๐ŸŸก Task claimed: ${task.id}`);
132
- console.log(` Title: ${task.title}`);
133
- console.log(` Agent: ${task.agent_id}`);
134
- console.log(` Status: ${task.status}\n`);
135
- } catch (e) {
136
- console.error(`\nโŒ ${e.message}\n`);
137
- }
138
- closeDb();
139
- });
140
-
141
- taskCmd
142
- .command('start <id>')
143
- .description('Start working on a task (โ†’ in_progress)')
144
- .action((id) => {
145
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
146
- try {
147
- // Claim first if still ready
148
- const task = tm.getTask(id);
149
- if (!task) { console.error(`\nโŒ Task not found: ${id}\n`); closeDb(); return; }
150
- if (task.status === 'ready') {
151
- tm.claimTask(id, 'cli-user');
152
- }
153
- const updated = tm.updateProgress(id, 1);
154
- console.log(`\n๐Ÿ”ต Task started: ${updated.id}`);
155
- console.log(` Title: ${updated.title}`);
156
- console.log(` Status: ${updated.status}\n`);
157
- } catch (e) {
158
- console.error(`\nโŒ ${e.message}\n`);
159
- }
160
- closeDb();
161
- });
162
-
163
- taskCmd
164
- .command('done <id>')
165
- .description('Complete a task (โ†’ done)')
166
- .option('-m, --message <text>', 'Completion summary', '')
167
- .action((id, opts) => {
168
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
169
- try {
170
- const task = tm.getTask(id);
171
- if (!task) { console.error(`\nโŒ Task not found: ${id}\n`); closeDb(); return; }
172
- // Auto-claim if still ready
173
- if (task.status === 'ready') {
174
- tm.claimTask(id, 'cli-user');
175
- }
176
- const updated = tm.completeTask(id, opts.message || 'Completed via CLI');
177
- console.log(`\nโœ… Task completed: ${updated.id}`);
178
- console.log(` Title: ${updated.title}`);
179
- console.log(` Status: ${updated.status}\n`);
180
- } catch (e) {
181
- console.error(`\nโŒ ${e.message}\n`);
182
- }
183
- closeDb();
184
- });
185
-
186
- taskCmd
187
- .command('approve <id>')
188
- .description('Approve a draft task (draft โ†’ ready)')
189
- .action((id) => {
190
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
191
- try {
192
- const task = tm.approveTask(id);
193
- console.log(`\nโฌœ Task approved: ${task.id}`);
194
- console.log(` Title: ${task.title}`);
195
- console.log(` Status: ${task.status}\n`);
196
- } catch (e) {
197
- console.error(`\nโŒ ${e.message}\n`);
198
- }
199
- closeDb();
200
- });
201
-
202
- taskCmd
203
- .command('reopen <id>')
204
- .description('Reopen a completed task (done โ†’ ready)')
205
- .action((id) => {
206
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
207
- try {
208
- const task = tm.reopenTask(id);
209
- console.log(`\n๐Ÿ”„ Task reopened: ${task.id}`);
210
- console.log(` Title: ${task.title}`);
211
- console.log(` Status: ${task.status}\n`);
212
- } catch (e) {
213
- console.error(`\nโŒ ${e.message}\n`);
214
- }
215
- closeDb();
216
- });
217
-
218
- taskCmd
219
- .command('abandon <id>')
220
- .description('Abandon a task (back to ready)')
221
- .option('-r, --reason <text>', 'Reason for abandoning', 'No reason given')
222
- .action((id, opts) => {
223
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
224
- try {
225
- const task = tm.abandonTask(id, opts.reason);
226
- console.log(`\nโšซ Task abandoned: ${task.id}`);
227
- console.log(` Title: ${task.title}`);
228
- console.log(` Status: ${task.status}\n`);
229
- } catch (e) {
230
- console.error(`\nโŒ ${e.message}\n`);
231
- }
232
- closeDb();
233
- });
234
-
235
- taskCmd
236
- .command('delete <id>')
237
- .description('Delete a task (draft/ready only)')
238
- .action((id) => {
239
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
240
- try {
241
- tm.deleteTask(id);
242
- console.log(`\n๐Ÿ—‘๏ธ Task deleted: ${id}\n`);
243
- } catch (e) {
244
- console.error(`\nโŒ ${e.message}\n`);
245
- }
246
- closeDb();
247
- });
248
-
249
- taskCmd
250
- .command('update <id>')
251
- .description('Update task fields')
252
- .option('-t, --title <text>', 'New title')
253
- .option('-d, --description <text>', 'New description')
254
- .option('-p, --priority <n>', 'New priority (1=high, 3=low)')
255
- .option('--phase <phase>', 'New phase')
256
- .option('-a, --acceptance <text>', 'Acceptance criteria')
257
- .action((id, opts) => {
258
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
259
- try {
260
- const fields = {};
261
- if (opts.title) fields.title = opts.title;
262
- if (opts.description) fields.description = opts.description;
263
- if (opts.priority) fields.priority = parseInt(opts.priority);
264
- if (opts.phase) fields.phase = opts.phase;
265
- if (opts.acceptance) fields.acceptance = opts.acceptance;
266
-
267
- if (Object.keys(fields).length === 0) {
268
- console.log('\nโš ๏ธ No fields specified. Use --title, --description, --priority, --phase, or --acceptance\n');
269
- closeDb();
270
- return;
271
- }
272
-
273
- const task = tm.updateTask(id, fields);
274
- console.log(`\n๐Ÿ“ Task updated: ${task.id}`);
275
- console.log(` Title: ${task.title}`);
276
- console.log(` Priority: P${task.priority}`);
277
- console.log(` Status: ${task.status}\n`);
278
- } catch (e) {
279
- console.error(`\nโŒ ${e.message}\n`);
280
- }
281
- closeDb();
282
- });
283
-
284
- // โ”€โ”€โ”€ Agent Commands (Project-Scoped) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
285
-
286
- const agentCmd = program.command('agent').description('Agent management (project-scoped)');
287
-
288
- agentCmd
289
- .command('create <id>')
290
- .description('Create a project-scoped agent with skills')
291
- .requiredOption('-P, --project <project>', 'Project ID (required)')
292
- .option('-n, --name <name>', 'Agent display name')
293
- .option('-s, --skills <list>', 'Comma-separated skills (e.g. "code,debug,refactor")')
294
- .option('--icon <icon>', 'Agent icon', '๐Ÿค–')
295
- .option('-c, --color <hex>', 'Agent color (hex)', '#8888a0')
296
- .action((id, opts) => {
297
- const am = require(path.join(SYMPHONY_ROOT, 'core', 'agent-manager'));
298
- try {
299
- const skills = opts.skills ? opts.skills.split(',').map(s => s.trim()) : [];
300
- const agent = am.createAgent(id, opts.project, opts.name || id, skills, {
301
- icon: opts.icon,
302
- color: opts.color,
303
- });
304
- console.log(`\nโœ… Agent created: ${agent.icon} ${agent.name} (${agent.id})`);
305
- console.log(` Project: ${agent.projectId}`);
306
- console.log(` Skills: ${agent.skills.length > 0 ? agent.skills.join(', ') : '(none)'}`);
307
- console.log(` Status: ${agent.status}\n`);
308
- } catch (e) {
309
- console.error(`\nโŒ ${e.message}\n`);
310
- }
311
- closeDb();
312
- });
313
-
314
- agentCmd
315
- .command('list')
316
- .description('List agents (optionally filter by project)')
317
- .option('-P, --project <project>', 'Filter by project ID')
318
- .option('-s, --status <status>', 'Filter by status (offline|idle|working)')
319
- .action((opts) => {
320
- const am = require(path.join(SYMPHONY_ROOT, 'core', 'agent-manager'));
321
- const agents = am.listAgents({
322
- project: opts.project || undefined,
323
- status: opts.status || undefined,
324
- });
325
-
326
- if (agents.length === 0) {
327
- console.log('\n๐Ÿค– No agents found\n');
328
- closeDb();
329
- return;
330
- }
331
-
332
- const statusIcon = { offline: 'โšซ', idle: '๐Ÿ’ค', working: '๐ŸŸข' };
333
- console.log(`\n๐Ÿค– Agents (${agents.length}):\n`);
334
-
335
- let currentProject = '';
336
- for (const a of agents) {
337
- if (a.projectId !== currentProject) {
338
- currentProject = a.projectId;
339
- console.log(` ๐Ÿ“ ${currentProject}`);
340
- }
341
- const icon = statusIcon[a.status] || 'โ“';
342
- const task = a.currentTask ? ` โ†’ ${a.currentTask}` : '';
343
- const skills = a.skills.length > 0 ? ` [${a.skills.join(', ')}]` : '';
344
- const session = a.sessionId ? ` ๐Ÿ”—` : '';
345
- console.log(` ${icon} ${a.icon} ${a.name} (${a.id}) โ€” ${a.status}${task}${skills}${session}`);
346
- }
347
- console.log('');
348
- closeDb();
349
- });
350
-
351
- agentCmd
352
- .command('show <id>')
353
- .description('Show agent details')
354
- .action((id) => {
355
- // Try project_agents first, fallback to legacy agents
356
- const am = require(path.join(SYMPHONY_ROOT, 'core', 'agent-manager'));
357
- const agent = am.getAgent(id);
358
- if (!agent) {
359
- // Fallback to legacy orchestrator
360
- const orchestrator = require(path.join(SYMPHONY_ROOT, 'core', 'orchestrator'));
361
- const legacy = orchestrator.getAgent(id);
362
- if (!legacy) {
363
- console.error(`\nโŒ Agent not found: ${id}\n`);
364
- closeDb();
365
- return;
366
- }
367
- const specs = legacy.specialties ? JSON.parse(legacy.specialties || '[]') : [];
368
- console.log(`\n๐Ÿค– Agent (legacy): ${legacy.name} (${legacy.id})`);
369
- console.log(` Status: ${legacy.status}`);
370
- console.log(` Specialties: ${specs.length > 0 ? specs.join(', ') : '(none)'}`);
371
- console.log(` Current Task: ${legacy.current_task_id || '(none)'}`);
372
- console.log('');
373
- closeDb();
374
- return;
375
- }
376
- console.log(`\n${agent.icon} Agent: ${agent.name} (${agent.id})`);
377
- console.log(` Project: ${agent.projectId}`);
378
- console.log(` Status: ${agent.status}`);
379
- console.log(` Skills: ${agent.skills.length > 0 ? agent.skills.join(', ') : '(none)'}`);
380
- console.log(` Current Task: ${agent.currentTask || '(none)'}`);
381
- console.log(` Session: ${agent.sessionId || '(detached)'}`);
382
- console.log(` Last Active: ${agent.lastActiveAt || '(never)'}`);
383
- console.log(` Idle Since: ${agent.idleSince || '-'}`);
384
- console.log(` Icon: ${agent.icon}`);
385
- console.log(` Color: ${agent.color}`);
386
- console.log(` Created: ${agent.createdAt}`);
387
- console.log('');
388
- closeDb();
389
- });
390
-
391
- agentCmd
392
- .command('update <id>')
393
- .description('Update agent config')
394
- .option('-n, --name <name>', 'New display name')
395
- .option('-s, --skills <list>', 'Comma-separated skills')
396
- .option('--icon <icon>', 'Agent icon')
397
- .option('-c, --color <hex>', 'Agent color (hex)')
398
- .action((id, opts) => {
399
- const am = require(path.join(SYMPHONY_ROOT, 'core', 'agent-manager'));
400
- try {
401
- const fields = {};
402
- if (opts.name) fields.name = opts.name;
403
- if (opts.skills) fields.skills = opts.skills.split(',').map(s => s.trim());
404
- if (opts.icon) fields.icon = opts.icon;
405
- if (opts.color) fields.color = opts.color;
406
-
407
- if (Object.keys(fields).length === 0) {
408
- console.log('\nโš ๏ธ No fields specified. Use --name, --skills, --icon, or --color\n');
409
- closeDb();
410
- return;
411
- }
412
-
413
- const agent = am.updateAgent(id, fields);
414
- console.log(`\n๐Ÿ“ Agent updated: ${agent.icon} ${agent.name} (${agent.id})`);
415
- console.log(` Skills: ${agent.skills.join(', ')}`);
416
- console.log(` Status: ${agent.status}\n`);
417
- } catch (e) {
418
- console.error(`\nโŒ ${e.message}\n`);
419
- }
420
- closeDb();
421
- });
422
-
423
- agentCmd
424
- .command('remove <id>')
425
- .description('Remove an agent config (must be offline)')
426
- .action((id) => {
427
- const am = require(path.join(SYMPHONY_ROOT, 'core', 'agent-manager'));
428
- try {
429
- am.removeAgent(id);
430
- console.log(`\n๐Ÿ—‘๏ธ Agent removed: ${id}\n`);
431
- } catch (e) {
432
- console.error(`\nโŒ ${e.message}\n`);
433
- }
434
- closeDb();
435
- });
436
-
437
- agentCmd
438
- .command('attach <id>')
439
- .description('Attach this window (session) to an agent')
440
- .option('--session <session>', 'Session/conversation ID', `cli-${Date.now()}`)
441
- .action((id, opts) => {
442
- const am = require(path.join(SYMPHONY_ROOT, 'core', 'agent-manager'));
443
- try {
444
- const agent = am.attachSession(id, opts.session);
445
- console.log(`\n๐Ÿ”— Attached to agent: ${agent.icon} ${agent.name}`);
446
- console.log(` Project: ${agent.projectId}`);
447
- console.log(` Skills: ${agent.skills.join(', ')}`);
448
- console.log(` Status: ${agent.status}`);
449
- console.log(` Session: ${agent.sessionId}\n`);
450
- } catch (e) {
451
- console.error(`\nโŒ ${e.message}\n`);
452
- }
453
- closeDb();
454
- });
455
-
456
- agentCmd
457
- .command('detach <id>')
458
- .description('Detach session from an agent (โ†’ offline)')
459
- .action((id) => {
460
- const am = require(path.join(SYMPHONY_ROOT, 'core', 'agent-manager'));
461
- try {
462
- const agent = am.detachSession(id);
463
- console.log(`\n๐Ÿ”Œ Detached from agent: ${agent.icon} ${agent.name}`);
464
- console.log(` Status: ${agent.status}\n`);
465
- } catch (e) {
466
- console.error(`\nโŒ ${e.message}\n`);
467
- }
468
- closeDb();
469
- });
470
-
471
- agentCmd
472
- .command('assign <agent-id> <task-id>')
473
- .description('Assign a task to a project agent')
474
- .action((agentId, taskId) => {
475
- const am = require(path.join(SYMPHONY_ROOT, 'core', 'agent-manager'));
476
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
477
- try {
478
- const agent = am.getAgent(agentId);
479
- if (!agent) throw new Error(`Agent not found: ${agentId}`);
480
- if (agent.status === 'offline') throw new Error(`Agent ${agentId} is offline. Attach first.`);
481
-
482
- const task = tm.claimTask(taskId, agentId);
483
- am.startWork(agentId, taskId);
484
-
485
- console.log(`\n๐ŸŽฏ Task dispatched:`);
486
- console.log(` Agent: ${agent.icon} ${agent.name} (${agentId})`);
487
- console.log(` Task: ${task.id} โ€” ${task.title}`);
488
- console.log(` Status: ${task.status}\n`);
489
- } catch (e) {
490
- console.error(`\nโŒ ${e.message}\n`);
491
- }
492
- closeDb();
493
- });
494
-
495
- agentCmd
496
- .command('idle <id>')
497
- .description('Mark an agent as idle')
498
- .action((id) => {
499
- const am = require(path.join(SYMPHONY_ROOT, 'core', 'agent-manager'));
500
- try {
501
- am.markIdle(id);
502
- console.log(`\n๐Ÿ’ค Agent marked idle: ${id}\n`);
503
- } catch (e) {
504
- // Fallback to legacy orchestrator
505
- try {
506
- const orchestrator = require(path.join(SYMPHONY_ROOT, 'core', 'orchestrator'));
507
- orchestrator.markIdle(id);
508
- console.log(`\n๐Ÿ’ค Agent marked idle (legacy): ${id}\n`);
509
- } catch (e2) {
510
- console.error(`\nโŒ ${e2.message}\n`);
511
- }
512
- }
513
- closeDb();
514
- });
515
-
516
- // Legacy: keep 'register' as alias for backward compat
517
- agentCmd
518
- .command('register <id>')
519
- .description('Register a legacy agent (use "create" for project-scoped)')
520
- .option('-n, --name <name>', 'Agent display name')
521
- .option('-s, --specialties <list>', 'Comma-separated specialties')
522
- .option('-c, --color <hex>', 'Agent color (hex)', '#8888a0')
523
- .action((id, opts) => {
524
- const orchestrator = require(path.join(SYMPHONY_ROOT, 'core', 'orchestrator'));
525
- try {
526
- orchestrator.registerAgent(id, opts.name || id);
527
- if (opts.specialties || opts.color !== '#8888a0') {
528
- orchestrator.updateAgentProfile(id, {
529
- specialties: opts.specialties ? opts.specialties.split(',').map(s => s.trim()) : undefined,
530
- color: opts.color,
531
- });
532
- }
533
- const agent = orchestrator.getAgent(id);
534
- console.log(`\n๐Ÿค– Agent registered (legacy): ${agent.name} (${agent.id})`);
535
- console.log(` ๐Ÿ’ก Use 'symphony agent create' for project-scoped agents\n`);
536
- } catch (e) {
537
- console.error(`\nโŒ ${e.message}\n`);
538
- }
539
- closeDb();
540
- });
541
-
542
- // โ”€โ”€โ”€ Dispatch Command (shortcut) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
543
-
544
- program
545
- .command('dispatch <task-id>')
546
- .description('๐ŸŽฏ Dispatch a task to the best available agent')
547
- .option('-a, --agent <id>', 'Specific agent to dispatch to')
548
- .action((taskId, opts) => {
549
- const orchestrator = require(path.join(SYMPHONY_ROOT, 'core', 'orchestrator'));
550
- try {
551
- let agentId = opts.agent;
552
-
553
- if (!agentId) {
554
- // Auto-select: find idle agent or the one with fewest tasks
555
- const agents = orchestrator.getAgents();
556
- const idle = agents.find(a => a.status === 'idle');
557
- if (idle) {
558
- agentId = idle.id;
559
- } else if (agents.length > 0) {
560
- // Pick agent with least work
561
- agentId = agents[0].id;
562
- } else {
563
- // No agents โ€” auto-register a default one
564
- agentId = 'auto-agent';
565
- orchestrator.registerAgent(agentId, 'Auto Agent');
566
- console.log(' ๐Ÿ“ Auto-registered agent: auto-agent');
567
- }
568
- } else {
569
- // Ensure agent exists
570
- if (!orchestrator.getAgent(agentId)) {
571
- orchestrator.registerAgent(agentId, agentId);
572
- }
573
- }
574
-
575
- const task = orchestrator.dispatchTask(agentId, taskId);
576
- console.log(`\n๐ŸŽฏ Dispatched:`);
577
- console.log(` Task: ${task.id} โ€” ${task.title}`);
578
- console.log(` Agent: ${agentId}`);
579
- console.log(` Status: ${task.status}\n`);
580
- } catch (e) {
581
- console.error(`\nโŒ ${e.message}\n`);
582
- }
583
- closeDb();
584
- });
585
-
586
- // โ”€โ”€โ”€ Next Command (AI helper) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
587
-
588
- program
589
- .command('next')
590
- .description('๐Ÿ“‹ Suggest the next task to work on')
591
- .option('-n, --count <n>', 'Number of suggestions', '3')
592
- .action((opts) => {
593
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
594
- const ready = tm.listTasks({ status: 'ready', limit: parseInt(opts.count) });
595
-
596
- if (ready.length === 0) {
597
- console.log('\nโœ… No tasks in queue โ€” all caught up!\n');
598
- closeDb();
599
- return;
600
- }
601
-
602
- console.log(`\n๐Ÿ“‹ Next task suggestions (${ready.length}):\n`);
603
- for (let i = 0; i < ready.length; i++) {
604
- const t = ready[i];
605
- console.log(` ${i + 1}. [P${t.priority}] ${t.title}`);
606
- console.log(` ID: ${t.id}`);
607
- if (t.description) console.log(` ${t.description.substring(0, 80)}`);
608
- console.log('');
609
- }
610
-
611
- console.log(` ๐Ÿ’ก Start working: symphony task start ${ready[0].id}`);
612
- console.log(` ๐ŸŽฏ Dispatch: symphony dispatch ${ready[0].id}\n`);
613
- closeDb();
614
- });
615
-
616
- // โ”€โ”€โ”€ Status Command โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
617
-
618
- program
619
- .command('status')
620
- .description('Show system status')
621
- .action(() => {
622
- const orchestrator = require(path.join(SYMPHONY_ROOT, 'core', 'orchestrator'));
623
- const status = orchestrator.getStatus();
624
-
625
- console.log('\n๐ŸŽผ AWKit Symphony Status\n');
626
-
627
- // Agents
628
- console.log(`๐Ÿค– Agents (${status.agents.length}/${status.config.maxAgents}):`);
629
- if (status.agents.length === 0) {
630
- console.log(' No agents connected\n');
631
- } else {
632
- for (const a of status.agents) {
633
- const taskInfo = a.currentTask ? ` โ†’ ${a.currentTask}` : '';
634
- console.log(` ${a.status === 'working' ? '๐ŸŸข' : '๐Ÿ’ค'} ${a.name} [${a.status}]${taskInfo}`);
635
- }
636
- console.log('');
637
- }
638
-
639
- // Task stats
640
- console.log('๐Ÿ“Š Tasks:');
641
- console.log(` โฌœ Ready: ${status.stats.ready}`);
642
- console.log(` ๐Ÿ”ต In Progress: ${status.stats.in_progress + status.stats.claimed}`);
643
- console.log(` ๐ŸŸฃ Review: ${status.stats.review}`);
644
- console.log(` โœ… Done: ${status.stats.done}`);
645
- console.log(` ๐Ÿ“‹ Total: ${status.stats.total}\n`);
646
-
647
- // File locks
648
- console.log(`๐Ÿ”’ File Locks (${status.lockedFiles.length}):`);
649
- if (status.lockedFiles.length === 0) {
650
- console.log(' No files locked\n');
651
- } else {
652
- for (const l of status.lockedFiles) {
653
- console.log(` ๐Ÿ”’ ${l.file} โ†’ ${l.agent} (${l.since})`);
654
- }
655
- console.log('');
656
- }
657
-
658
- closeDb();
659
- });
660
-
661
- // โ”€โ”€โ”€ Preflight Command โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
662
-
663
- program
664
- .command('preflight')
665
- .description('๐Ÿšฆ Gate check โ€” mandatory first action every session')
666
- .option('-p, --project <id>', 'Project ID to scope preflight')
667
- .option('--json', 'Output as JSON')
668
- .action(async (opts) => {
669
- const http = require('http');
670
-
671
- // Try API first (server already running)
672
- const url = `http://localhost:3100/api/preflight${opts.project ? `?project=${opts.project}` : ''}`;
673
-
674
- try {
675
- const data = await new Promise((resolve, reject) => {
676
- const req = http.get(url, { timeout: 2000 }, (res) => {
677
- let body = '';
678
- res.on('data', (chunk) => body += chunk);
679
- res.on('end', () => {
680
- if (res.statusCode === 200) resolve(JSON.parse(body));
681
- else reject(new Error(`HTTP ${res.statusCode}`));
682
- });
683
- });
684
- req.on('error', reject);
685
- req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
686
- });
687
-
688
- if (opts.json) {
689
- console.log(JSON.stringify(data, null, 2));
690
- } else {
691
- printPreflight(data);
692
- }
693
- } catch (_) {
694
- // Fallback: direct DB query (server not running)
695
- console.log('โš ๏ธ Symphony server not running โ€” using direct DB\n');
696
- try {
697
- const tm = require(path.join(SYMPHONY_ROOT, 'core', 'task-manager'));
698
- const inProgress = tm.listTasks({ status: 'in_progress', limit: 10 });
699
- const claimed = tm.listTasks({ status: 'claimed', limit: 10 });
700
- const ready = tm.listTasks({ status: 'ready', limit: 5 });
701
-
702
- const fallbackData = {
703
- gate_status: 'WARN',
704
- gates: { server: 'OFFLINE', project: 'UNKNOWN', tasks: inProgress.length > 0 || claimed.length > 0 ? 'HAS_ACTIVE' : 'EMPTY', agents: 'UNKNOWN' },
705
- server: { status: 'offline' },
706
- active_project: null,
707
- projects: [],
708
- tasks: {
709
- stats: { total: inProgress.length + claimed.length + ready.length },
710
- in_progress: [...inProgress, ...claimed].map(t => ({ id: t.id, title: t.title, priority: t.priority })),
711
- ready: ready.map(t => ({ id: t.id, title: t.title, priority: t.priority })),
712
- },
713
- agents: [],
714
- };
715
-
716
- if (opts.json) {
717
- console.log(JSON.stringify(fallbackData, null, 2));
718
- } else {
719
- printPreflight(fallbackData);
720
- }
721
- } catch (dbErr) {
722
- console.log('โŒ Cannot connect to Symphony server or database.\n');
723
- console.log(' Start server: symphony start');
724
- console.log(' Or install: cd ~/Dev/NodeJS/main-awf/symphony && npm link\n');
725
- process.exit(1);
726
- }
727
- }
728
- closeDb();
729
- });
730
-
731
- function printPreflight(data) {
732
- const gateIcon = (g) => g === 'PASS' ? 'โœ…' : g === 'WARN' || g === 'OFFLINE' || g === 'UNKNOWN' ? 'โš ๏ธ' : g === 'FAIL' ? 'โŒ' : '๐Ÿ”ต';
733
-
734
- console.log('\n๐Ÿšฆ SYMPHONY PREFLIGHT');
735
- console.log('โ”€'.repeat(50));
736
- console.log(` Server: ${gateIcon(data.gates.server)} ${data.gates.server}`);
737
- console.log(` Project: ${gateIcon(data.gates.project)} ${data.gates.project}${data.active_project ? ` โ€” ${data.active_project.icon || '๐Ÿ“'} ${data.active_project.name}` : ''}`);
738
- console.log(` Tasks: ${gateIcon(data.gates.tasks)} ${data.gates.tasks}`);
739
- if (data.gates.agents) {
740
- console.log(` Agents: ${gateIcon(data.gates.agents)} ${data.gates.agents}`);
741
- }
742
- console.log(` Overall: ${data.gate_status === 'PASS' ? 'โœ… PASS' : 'โš ๏ธ ' + data.gate_status}\n`);
743
-
744
- // Projects
745
- if (data.projects && data.projects.length > 0) {
746
- console.log(`๐Ÿ“ Projects (${data.projects.length}):`);
747
- for (const p of data.projects) {
748
- console.log(` ${p.active ? 'โ—' : 'โ—‹'} ${p.icon || '๐Ÿ“'} ${p.name} [${p.id}]`);
749
- }
750
- console.log('');
751
- }
752
-
753
- // Agents
754
- if (data.agents && data.agents.length > 0) {
755
- const statusIcon = { offline: 'โšซ', idle: '๐Ÿ’ค', working: '๐ŸŸข' };
756
- console.log(`๐Ÿค– Agents (${data.agents.length}):`);
757
- for (const a of data.agents) {
758
- const icon = statusIcon[a.status] || 'โ“';
759
- const skills = a.skills && a.skills.length > 0 ? ` [${a.skills.join(', ')}]` : '';
760
- const task = a.currentTask ? ` โ†’ ${a.currentTask}` : '';
761
- console.log(` ${icon} ${a.icon || '๐Ÿค–'} ${a.name} (${a.id})${skills}${task}`);
762
- }
763
- console.log('');
764
- }
765
-
766
- // In-progress tasks
767
- if (data.tasks.in_progress && data.tasks.in_progress.length > 0) {
768
- console.log(`๐Ÿ“ฟ In Progress (${data.tasks.in_progress.length}):`);
769
- for (const t of data.tasks.in_progress) {
770
- console.log(` ๐Ÿ”ต ${t.id} โ€” ${t.title} (P${t.priority})`);
771
- }
772
- console.log('');
773
- } else {
774
- console.log('๐Ÿ“ฟ In Progress: none\n');
775
- }
776
-
777
- // Ready tasks
778
- if (data.tasks.ready && data.tasks.ready.length > 0) {
779
- console.log(`๐Ÿ“‹ Ready (${data.tasks.ready.length}):`);
780
- for (const t of data.tasks.ready) {
781
- console.log(` โฌœ ${t.id} โ€” ${t.title} (P${t.priority})`);
782
- }
783
- console.log('');
784
- } else {
785
- console.log('๐Ÿ“‹ Ready: none\n');
786
- }
787
- }
788
-
789
- // โ”€โ”€โ”€ Lock Commands โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
790
-
791
- const lockCmd = program.command('lock').description('File lock management');
792
-
793
- lockCmd
794
- .command('list')
795
- .description('List all file locks')
796
- .action(() => {
797
- const flm = require(path.join(SYMPHONY_ROOT, 'core', 'file-lock-manager'));
798
- const locks = flm.getAllLocks();
799
-
800
- if (locks.length === 0) {
801
- console.log('\n๐ŸŸข No files locked\n');
802
- closeDb();
803
- return;
804
- }
805
-
806
- console.log(`\n๐Ÿ”’ Active File Locks (${locks.length}):\n`);
807
- for (const l of locks) {
808
- console.log(` ${l.file_path}`);
809
- console.log(` โ””โ”€ Agent: ${l.agent_id} | Task: ${l.task_id} | Since: ${l.acquired_at}`);
810
- }
811
- console.log('');
812
- closeDb();
813
- });
814
-
815
- lockCmd
816
- .command('release <file>')
817
- .description('Force-release a file lock')
818
- .action((file) => {
819
- const flm = require(path.join(SYMPHONY_ROOT, 'core', 'file-lock-manager'));
820
- const released = flm.forceRelease(file);
821
- if (released) {
822
- console.log(`\nโœ… Lock released: ${file}\n`);
823
- } else {
824
- console.log(`\nโš ๏ธ No lock found for: ${file}\n`);
825
- }
826
- closeDb();
827
- });
828
-
829
- // โ”€โ”€โ”€ Workspace Commands โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
830
-
831
- const wsCmd = program.command('workspace').alias('ws').description('Workspace management');
832
-
833
- wsCmd
834
- .command('list')
835
- .description('List active workspaces')
836
- .action(() => {
837
- const wm = require(path.join(SYMPHONY_ROOT, 'core', 'workspace-manager'));
838
- const workspaces = wm.listWorkspaces();
839
-
840
- if (workspaces.length === 0) {
841
- console.log('\n๐Ÿ“‚ No active workspaces\n');
842
- closeDb();
843
- return;
844
- }
845
-
846
- console.log(`\n๐Ÿ“‚ Active Workspaces (${workspaces.length}):\n`);
847
- for (const ws of workspaces) {
848
- console.log(` ${ws.branch}`);
849
- console.log(` โ””โ”€ Task: ${ws.task_id} | Type: ${ws.type} | Path: ${ws.path}`);
850
- console.log(` Created: ${ws.created_at}`);
851
- }
852
- console.log('');
853
- closeDb();
854
- });
855
-
856
- wsCmd
857
- .command('create <task-id>')
858
- .description('Create workspace for a task')
859
- .option('-t, --type <type>', 'Workspace type (worktree|clone)', 'worktree')
860
- .action((taskId, opts) => {
861
- const wm = require(path.join(SYMPHONY_ROOT, 'core', 'workspace-manager'));
862
- const repoPath = process.cwd();
863
-
864
- try {
865
- const ws = wm.createWorkspace(taskId, repoPath, { type: opts.type });
866
- console.log(`\nโœ… Workspace created:`);
867
- console.log(` Branch: ${ws.branch}`);
868
- console.log(` Path: ${ws.path}`);
869
- console.log(` Type: ${ws.type}\n`);
870
- } catch (e) {
871
- console.error(`\nโŒ Failed to create workspace: ${e.message}\n`);
872
- }
873
- closeDb();
874
- });
875
-
876
- wsCmd
877
- .command('merge <task-id>')
878
- .description('Run auto-merge pipeline for a completed task')
879
- .action((taskId) => {
880
- const mp = require(path.join(SYMPHONY_ROOT, 'core', 'merge-pipeline'));
881
- const repoPath = process.cwd();
882
-
883
- console.log(`\n๐Ÿ”€ Running merge pipeline for task ${taskId}...\n`);
884
- const result = mp.autoMerge(taskId, repoPath);
885
-
886
- if (result.status === 'merged') {
887
- console.log(` โœ… ${result.message}\n`);
888
- } else if (result.status === 'conflict') {
889
- console.log(` โš ๏ธ ${result.message}`);
890
- if (result.conflictingFiles && result.conflictingFiles.length > 0) {
891
- console.log(' Conflicting files:');
892
- for (const f of result.conflictingFiles) {
893
- console.log(` - ${f}`);
894
- }
895
- }
896
- console.log('');
897
- } else {
898
- console.error(` โŒ ${result.message}\n`);
899
- }
900
- closeDb();
901
- });
902
-
903
- wsCmd
904
- .command('clean')
905
- .description('Remove all completed/merged workspaces')
906
- .action(() => {
907
- const { getDb } = require(path.join(SYMPHONY_ROOT, 'core', 'db'));
908
- const wm = require(path.join(SYMPHONY_ROOT, 'core', 'workspace-manager'));
909
- const db = getDb();
910
-
911
- const merged = db.prepare("SELECT * FROM workspaces WHERE status IN ('merged', 'cleaned')").all();
912
- if (merged.length === 0) {
913
- console.log('\n๐ŸŸข No workspaces to clean\n');
914
- closeDb();
915
- return;
916
- }
917
-
918
- let cleaned = 0;
919
- for (const ws of merged) {
920
- if (ws.status !== 'cleaned') {
921
- try {
922
- wm.removeWorkspace(ws.task_id, process.cwd());
923
- cleaned++;
924
- } catch (_) { /* skip */ }
925
- }
926
- }
927
- console.log(`\n๐Ÿงน Cleaned ${cleaned} workspace(s)\n`);
928
- closeDb();
929
- });
930
-
931
- // โ”€โ”€โ”€ Dashboard Command โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
932
-
933
- program
934
- .command('dashboard')
935
- .description('Open dashboard in browser')
936
- .action(() => {
937
- const config = require(path.join(SYMPHONY_ROOT, 'symphony.config'));
938
- const url = `http://localhost:${config.port}`;
939
- console.log(`\n๐ŸŒ Opening dashboard: ${url}\n`);
940
- try {
941
- require('child_process').execSync(`open "${url}"`, { stdio: 'ignore' });
942
- } catch (_) {
943
- console.log(` Open manually: ${url}`);
944
- }
945
- });
946
-
947
- // โ”€โ”€โ”€ MCP Serve Command โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
948
-
949
- program
950
- .command('mcp-serve')
951
- .description('Start MCP server (stdio transport for IDE connections)')
952
- .option('-n, --name <name>', 'Agent display name')
953
- .action((opts) => {
954
- // Set agent name env var before requiring the server
955
- if (opts.name) {
956
- process.env.SYMPHONY_AGENT_NAME = opts.name;
957
- }
958
- // The MCP server takes over stdio, so we require it directly
959
- require(path.join(SYMPHONY_ROOT, 'mcp', 'server'));
960
- });
961
-
962
- // โ”€โ”€โ”€ Build Command โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
963
-
964
- program
965
- .command('build')
966
- .description('Build Symphony dashboard for production')
967
- .action(() => {
968
- console.log('\n๐Ÿ“ฆ Building Symphony dashboard...\n');
969
- const { execSync } = require('child_process');
970
- try {
971
- execSync('npx next build', {
972
- cwd: SYMPHONY_ROOT,
973
- stdio: 'inherit',
974
- env: { ...process.env, NODE_ENV: 'production' },
975
- });
976
- console.log('\nโœ… Build complete!\n');
977
- } catch (err) {
978
- console.error('\nโŒ Build failed.\n');
979
- process.exit(1);
980
- }
981
- });
982
-
983
- // โ”€โ”€โ”€ Start Command โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
984
-
985
- program
986
- .command('start')
987
- .description('Start Symphony server (dashboard + API) in production mode')
988
- .option('-p, --port <port>', 'Port number', '3100')
989
- .action((opts) => {
990
- const { execSync } = require('child_process');
991
- const fs = require('fs');
992
-
993
- // Auto-build if .next/ doesn't exist
994
- if (!fs.existsSync(path.join(SYMPHONY_ROOT, '.next'))) {
995
- console.log('\n๐Ÿ“ฆ First run โ€” building dashboard...\n');
996
- try {
997
- execSync('npx next build', {
998
- cwd: SYMPHONY_ROOT,
999
- stdio: 'inherit',
1000
- env: { ...process.env, NODE_ENV: 'production' },
1001
- });
1002
- } catch (err) {
1003
- console.error('\nโŒ Build failed. Try running: symphony build\n');
1004
- process.exit(1);
1005
- }
1006
- }
1007
-
1008
- console.log(`\n๐ŸŽผ Starting AWKit Symphony on port ${opts.port}...\n`);
1009
- try {
1010
- execSync(`npx next start -p ${opts.port}`, {
1011
- cwd: SYMPHONY_ROOT,
1012
- stdio: 'inherit',
1013
- });
1014
- } catch (_) {
1015
- // Interrupted (Ctrl+C)
1016
- }
1017
- });
1018
-
1019
- // โ”€โ”€โ”€ Dev Command โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
1020
-
1021
- program
1022
- .command('dev')
1023
- .description('Start Symphony in development mode (hot reload)')
1024
- .option('-p, --port <port>', 'Port number', '3100')
1025
- .action((opts) => {
1026
- console.log(`\n๐Ÿ”ง Starting AWKit Symphony (dev) on port ${opts.port}...\n`);
1027
- const { execSync } = require('child_process');
1028
- try {
1029
- execSync(`npx next dev -p ${opts.port}`, {
1030
- cwd: SYMPHONY_ROOT,
1031
- stdio: 'inherit',
1032
- });
1033
- } catch (_) {
1034
- // Interrupted (Ctrl+C)
1035
- }
1036
- });
1037
-
1038
- function closeDb() {
1039
- try {
1040
- require(path.join(SYMPHONY_ROOT, 'core', 'db')).close();
1041
- } catch (_) { /* ignore */ }
1042
- }
1043
-
1044
- // โ”€โ”€โ”€ Global Error Handling โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
1045
-
1046
- process.on('uncaughtException', (err) => {
1047
- console.error(`\nโŒ Unexpected error: ${err.message}\n`);
1048
- if (process.env.DEBUG) console.error(err.stack);
1049
- closeDb();
1050
- process.exit(1);
1051
- });
1052
-
1053
- process.on('unhandledRejection', (reason) => {
1054
- console.error(`\nโŒ Unhandled rejection: ${reason}\n`);
1055
- closeDb();
1056
- process.exit(1);
1057
- });
1058
-
1059
- program.parse();
1060
-