@phantom-pm/cli 1.0.0 → 1.1.0-beta.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.
- package/dist/commands/chat.d.ts +6 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +342 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +14 -3
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/dashboard.d.ts +4 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +59 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/task.d.ts +4 -0
- package/dist/commands/task.d.ts.map +1 -0
- package/dist/commands/task.js +40 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/index.js +1184 -211
- package/dist/index.js.map +1 -1
- package/dist/postinstall.d.ts +3 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +22 -0
- package/dist/postinstall.js.map +1 -0
- package/package.json +22 -5
package/dist/index.js
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
// ╔══════════════════════════════════════════════════════════════════╗
|
|
4
|
+
// ║ PHANTOM CLI — "Follow the white rabbit." ║
|
|
5
|
+
// ║ ║
|
|
6
|
+
// ║ The command-line gateway to the Phantom PM Operating System. ║
|
|
7
|
+
// ║ Every `phantom` command starts here — chat, swarm, prd, ║
|
|
8
|
+
// ║ simulate, agents, mcp, and 17 module superpowers. ║
|
|
9
|
+
// ╚══════════════════════════════════════════════════════════════════╝
|
|
10
|
+
import { existsSync, readdirSync, statSync } from 'fs';
|
|
3
11
|
import { basename, join, resolve } from 'path';
|
|
4
12
|
import { Command } from 'commander';
|
|
5
13
|
import { PHANTOM_ASCII, PHANTOM_VERSION, TAGLINE, FRAMEWORKS, getConfig, getContextEngine, getModuleManager, getSwarm, KNOWN_INTEGRATION_TARGETS, isKnownIntegrationTarget, scanIntegrations as scanIntegrationTargets, connectIntegration as connectIntegrationTarget, doctorIntegrations, analyzeScreenPath, auditScreensPath, generateRealDocumentation, getRealProducts, getRuntimeHealth, runDeterministicSimulation, } from '@phantom-pm/core';
|
|
14
|
+
import { registerWithAllDetected, registerWithSpecificAgent, listRegistrationTargets, } from '@phantom-pm/core';
|
|
6
15
|
import { registerConfigCommands } from './commands/config.js';
|
|
7
16
|
import { registerStoriesCommands } from './commands/stories.js';
|
|
17
|
+
import { startChat } from './commands/chat.js';
|
|
18
|
+
import { TaskAnalyze } from './commands/task.js';
|
|
8
19
|
import { PhantomMCPServer, runStdioServer, PhantomDiscovery } from '@phantom-pm/mcp-server';
|
|
9
20
|
import { theme, box, runBootSequence, showFirstRunSetup, renderModuleInstall, renderModuleStore, renderSwarmResult, renderHealthDashboard, } from '@phantom-pm/tui';
|
|
10
21
|
const program = new Command();
|
|
@@ -27,6 +38,31 @@ function failNotImplemented(command) {
|
|
|
27
38
|
console.error('');
|
|
28
39
|
process.exitCode = 1;
|
|
29
40
|
}
|
|
41
|
+
function asObject(value) {
|
|
42
|
+
if (!value || typeof value !== 'object')
|
|
43
|
+
return {};
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
async function runModuleCommand(moduleName, moduleLabel, commandName, args) {
|
|
47
|
+
const moduleManager = getModuleManager();
|
|
48
|
+
if (!moduleManager.isInstalled(moduleName)) {
|
|
49
|
+
console.log('');
|
|
50
|
+
console.log(theme.warning(` ${moduleLabel} module not installed. Installing...`));
|
|
51
|
+
await moduleManager.install(moduleName);
|
|
52
|
+
}
|
|
53
|
+
const result = await moduleManager.executeCommand(moduleName, commandName, args);
|
|
54
|
+
return asObject(result);
|
|
55
|
+
}
|
|
56
|
+
function parseJsonOption(raw, optionName) {
|
|
57
|
+
if (!raw)
|
|
58
|
+
return undefined;
|
|
59
|
+
try {
|
|
60
|
+
return JSON.parse(raw);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
throw new Error(`Invalid JSON for ${optionName}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
30
66
|
program
|
|
31
67
|
.name('phantom')
|
|
32
68
|
.description(TAGLINE)
|
|
@@ -288,14 +324,80 @@ mcpCommand
|
|
|
288
324
|
mcpCommand
|
|
289
325
|
.command('serve')
|
|
290
326
|
.description('Run MCP server over stdio')
|
|
291
|
-
.option('--mode <mode>', '
|
|
327
|
+
.option('--mode <mode>', 'Transport mode (stdio, legacy-jsonl)', 'stdio')
|
|
328
|
+
.option('--tools <mode>', 'Tool loading mode (core, standard, all)', 'standard')
|
|
329
|
+
.action(async (options) => {
|
|
330
|
+
const transportMode = options.mode === 'legacy-jsonl' ? 'legacy-jsonl' : 'stdio';
|
|
331
|
+
if (options.mode !== 'stdio' && options.mode !== 'legacy-jsonl') {
|
|
332
|
+
console.log('');
|
|
333
|
+
console.log(theme.warning(` Unsupported transport mode '${options.mode}', using stdio.`));
|
|
334
|
+
console.log('');
|
|
335
|
+
}
|
|
336
|
+
// Validate tool mode
|
|
337
|
+
const validToolModes = ['core', 'standard', 'all'];
|
|
338
|
+
const toolMode = validToolModes.includes(options.tools) ? options.tools : 'standard';
|
|
339
|
+
if (!validToolModes.includes(options.tools)) {
|
|
340
|
+
console.log(theme.warning(` Unsupported tool mode '${options.tools}', using standard.`));
|
|
341
|
+
}
|
|
342
|
+
await runStdioServer(transportMode, toolMode);
|
|
343
|
+
});
|
|
344
|
+
mcpCommand
|
|
345
|
+
.command('status')
|
|
346
|
+
.description('Check MCP integration status')
|
|
347
|
+
.option('--json', 'Output as JSON')
|
|
292
348
|
.action(async (options) => {
|
|
293
|
-
|
|
349
|
+
const { PhantomDiscovery } = await import('@phantom-pm/mcp-server');
|
|
350
|
+
const report = await PhantomDiscovery.healthReport();
|
|
351
|
+
if (options.json) {
|
|
352
|
+
printJson(report);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
console.log('');
|
|
356
|
+
console.log(theme.title(' MCP INTEGRATION STATUS'));
|
|
357
|
+
console.log('');
|
|
358
|
+
// Check MCP server
|
|
359
|
+
const mcpRunning = report.mcp_server.status === 'running';
|
|
360
|
+
console.log(` ${theme.secondary('MCP Server:')} ${mcpRunning ? theme.success('Running') : theme.error('Not responding')}`);
|
|
361
|
+
// Check agent registrations
|
|
362
|
+
const agents = report.agents;
|
|
363
|
+
const installedAgents = agents.filter(agent => agent.installed);
|
|
364
|
+
if (installedAgents.length === 0) {
|
|
294
365
|
console.log('');
|
|
295
|
-
console.log(theme.warning(
|
|
366
|
+
console.log(theme.warning(' No AI agents detected on this system.'));
|
|
367
|
+
console.log(theme.dim(' Install Cursor, Codex, or other MCP-compatible editors to enable integration.'));
|
|
296
368
|
console.log('');
|
|
369
|
+
return;
|
|
297
370
|
}
|
|
298
|
-
|
|
371
|
+
console.log('');
|
|
372
|
+
console.log(theme.secondary(` Detected Agents (${installedAgents.length}):`));
|
|
373
|
+
for (const agent of installedAgents) {
|
|
374
|
+
const status = agent.registered ? theme.success('Registered') : theme.warning('Not registered');
|
|
375
|
+
console.log(` ${agent.name}: ${status}`);
|
|
376
|
+
}
|
|
377
|
+
console.log('');
|
|
378
|
+
if (mcpRunning && installedAgents.some(agent => agent.registered)) {
|
|
379
|
+
console.log(theme.success(' ✅ MCP integration is ready!'));
|
|
380
|
+
console.log(theme.dim(' Restart your AI agents to enable PHANTOM integration.'));
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
console.log(theme.warning(' ⚠️ MCP integration needs attention.'));
|
|
384
|
+
console.log(theme.dim(' Run "phantom mcp register" to register with agents.'));
|
|
385
|
+
}
|
|
386
|
+
console.log('');
|
|
387
|
+
});
|
|
388
|
+
mcpCommand
|
|
389
|
+
.command('register')
|
|
390
|
+
.description('Manually register with detected AI agents')
|
|
391
|
+
.action(async () => {
|
|
392
|
+
const { PhantomDiscovery } = await import('@phantom-pm/mcp-server');
|
|
393
|
+
console.log('');
|
|
394
|
+
console.log(theme.title(' MCP REGISTRATION'));
|
|
395
|
+
console.log('');
|
|
396
|
+
await PhantomDiscovery.autoRegisterAll();
|
|
397
|
+
console.log('');
|
|
398
|
+
console.log(theme.success(' Registration process completed!'));
|
|
399
|
+
console.log(theme.dim(' Restart your AI agents to enable PHANTOM integration.'));
|
|
400
|
+
console.log('');
|
|
299
401
|
});
|
|
300
402
|
program
|
|
301
403
|
.command('status')
|
|
@@ -392,6 +494,92 @@ program
|
|
|
392
494
|
}
|
|
393
495
|
console.log('');
|
|
394
496
|
});
|
|
497
|
+
program
|
|
498
|
+
.command('register')
|
|
499
|
+
.description('Register Phantom MCP server with detected AI agents')
|
|
500
|
+
.option('--target <agent>', 'Register with a specific agent (e.g. cursor, claude-code)')
|
|
501
|
+
.option('--all', 'Register with ALL detected agents')
|
|
502
|
+
.option('--list', 'List all registration targets and their status')
|
|
503
|
+
.option('--json', 'Output as JSON')
|
|
504
|
+
.action(async (options) => {
|
|
505
|
+
try {
|
|
506
|
+
const cwd = process.cwd();
|
|
507
|
+
if (options.list) {
|
|
508
|
+
const targets = listRegistrationTargets(cwd);
|
|
509
|
+
if (options.json) {
|
|
510
|
+
printJson({ targets });
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
console.log('');
|
|
514
|
+
console.log(theme.title(' MCP REGISTRATION TARGETS'));
|
|
515
|
+
console.log('');
|
|
516
|
+
for (const t of targets) {
|
|
517
|
+
const statusIcon = t.registered ? theme.success('✓ Registered') :
|
|
518
|
+
t.exists ? theme.warning('○ Not registered') :
|
|
519
|
+
theme.dim('— Config not found');
|
|
520
|
+
console.log(` ${theme.accent(t.agentName.padEnd(30))} ${statusIcon}`);
|
|
521
|
+
console.log(` ${theme.dim(t.configPath)}`);
|
|
522
|
+
console.log('');
|
|
523
|
+
}
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
if (options.target) {
|
|
527
|
+
const result = registerWithSpecificAgent(cwd, options.target);
|
|
528
|
+
if (options.json) {
|
|
529
|
+
printJson(result);
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
console.log('');
|
|
533
|
+
if (result.success) {
|
|
534
|
+
console.log(theme.success(` ✓ Phantom MCP registered with ${result.agentName}`));
|
|
535
|
+
console.log(` ${theme.secondary('Config:')} ${result.configPath}`);
|
|
536
|
+
console.log(` ${theme.secondary('Action:')} ${result.action}`);
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
console.log(theme.error(` ✗ Failed: ${result.message}`));
|
|
540
|
+
}
|
|
541
|
+
console.log('');
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
// Default: register with all detected agents
|
|
545
|
+
const summary = await registerWithAllDetected(cwd);
|
|
546
|
+
if (options.json) {
|
|
547
|
+
printJson(summary);
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
console.log('');
|
|
551
|
+
console.log(theme.title(' PHANTOM MCP AUTO-REGISTRATION'));
|
|
552
|
+
console.log('');
|
|
553
|
+
for (const result of summary.results) {
|
|
554
|
+
const icon = result.success
|
|
555
|
+
? (result.action === 'skipped' ? '○' : '✓')
|
|
556
|
+
: '✗';
|
|
557
|
+
const color = result.success
|
|
558
|
+
? (result.action === 'skipped' ? theme.dim : theme.success)
|
|
559
|
+
: theme.error;
|
|
560
|
+
console.log(` ${color(`${icon} ${result.agentName}`)} — ${result.message}`);
|
|
561
|
+
}
|
|
562
|
+
console.log('');
|
|
563
|
+
console.log(theme.secondary(` Total: ${summary.totalTargets} | Registered: ${summary.successful} | Skipped: ${summary.skipped} | Errors: ${summary.errors}`));
|
|
564
|
+
if (summary.successful > 0) {
|
|
565
|
+
console.log('');
|
|
566
|
+
console.log(theme.success(' Restart your AI agents to activate Phantom integration.'));
|
|
567
|
+
}
|
|
568
|
+
console.log('');
|
|
569
|
+
}
|
|
570
|
+
catch (err) {
|
|
571
|
+
const message = err instanceof Error ? err.message : 'Registration failed';
|
|
572
|
+
if (options.json) {
|
|
573
|
+
printJson({ status: 'error', error: message });
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
console.log('');
|
|
577
|
+
console.log(theme.error(` ${message}`));
|
|
578
|
+
console.log('');
|
|
579
|
+
}
|
|
580
|
+
process.exitCode = 1;
|
|
581
|
+
}
|
|
582
|
+
});
|
|
395
583
|
const prdCommand = program.command('prd').description('PRD operations');
|
|
396
584
|
// Register config commands
|
|
397
585
|
registerConfigCommands(program);
|
|
@@ -419,9 +607,9 @@ prdCommand
|
|
|
419
607
|
technical: options.technical,
|
|
420
608
|
ux: options.ux,
|
|
421
609
|
metrics: options.metrics,
|
|
422
|
-
output: options.out || '
|
|
610
|
+
output: options.out || './.phantom/output/prds',
|
|
423
611
|
});
|
|
424
|
-
const outputPath = result.prd.filePath || '
|
|
612
|
+
const outputPath = result.prd.filePath || './.phantom/output/prds';
|
|
425
613
|
const payload = {
|
|
426
614
|
status: 'ok',
|
|
427
615
|
module: 'prd-forge',
|
|
@@ -456,10 +644,10 @@ prdCommand
|
|
|
456
644
|
});
|
|
457
645
|
prdCommand
|
|
458
646
|
.command('list')
|
|
459
|
-
.description('List generated PRDs from phantom
|
|
647
|
+
.description('List generated PRDs from .phantom/output/prds directory')
|
|
460
648
|
.option('--json', 'Output as JSON')
|
|
461
649
|
.action((options) => {
|
|
462
|
-
const outDir = join(process.cwd(), 'phantom
|
|
650
|
+
const outDir = join(process.cwd(), '.phantom', 'output', 'prds');
|
|
463
651
|
const items = existsSync(outDir)
|
|
464
652
|
? readdirSync(outDir)
|
|
465
653
|
.filter(file => file.endsWith('.md'))
|
|
@@ -481,7 +669,7 @@ prdCommand
|
|
|
481
669
|
console.log(theme.title(' PRD LIBRARY'));
|
|
482
670
|
console.log('');
|
|
483
671
|
if (items.length === 0) {
|
|
484
|
-
console.log(theme.warning(' No PRDs found in phantom
|
|
672
|
+
console.log(theme.warning(' No PRDs found in .phantom/output/prds/.'));
|
|
485
673
|
}
|
|
486
674
|
else {
|
|
487
675
|
for (const item of items) {
|
|
@@ -515,9 +703,18 @@ program
|
|
|
515
703
|
console.log(theme.error(` ${message}`));
|
|
516
704
|
console.log('');
|
|
517
705
|
}
|
|
518
|
-
process.exitCode = 1;
|
|
519
706
|
}
|
|
520
707
|
});
|
|
708
|
+
program
|
|
709
|
+
.command('task')
|
|
710
|
+
.description('Deep task analysis and decomposition')
|
|
711
|
+
.command('analyze <goal>')
|
|
712
|
+
.description('Recursively decompose a goal into subtasks')
|
|
713
|
+
.action(async (goal) => {
|
|
714
|
+
// We need to render the React component
|
|
715
|
+
const { render } = await import('ink');
|
|
716
|
+
render(_jsx(TaskAnalyze, { goal: goal }));
|
|
717
|
+
});
|
|
521
718
|
const screenCommand = program.command('screen').description('Screen analysis commands');
|
|
522
719
|
screenCommand
|
|
523
720
|
.command('analyze <path>')
|
|
@@ -627,7 +824,7 @@ program
|
|
|
627
824
|
.option('--refresh', 'Generate new nudges based on current context')
|
|
628
825
|
.action(async (options) => {
|
|
629
826
|
try {
|
|
630
|
-
const { NudgeEngine, getConfig, getContextEngine, getModuleManager } = await import('@phantom/core');
|
|
827
|
+
const { NudgeEngine, getConfig, getContextEngine, getModuleManager } = await import('@phantom-pm/core');
|
|
631
828
|
const engine = new NudgeEngine();
|
|
632
829
|
// Handle dismiss/snooze actions
|
|
633
830
|
if (options.dismiss) {
|
|
@@ -1178,27 +1375,32 @@ analyticsCommand
|
|
|
1178
1375
|
console.log(` ${theme.accent('phantom analytics dashboard --categories "user-engagement,revenue"')}`);
|
|
1179
1376
|
console.log('');
|
|
1180
1377
|
});
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
.
|
|
1184
|
-
.
|
|
1378
|
+
const oracleCommand = program.command('oracle').description('Predictive product intelligence');
|
|
1379
|
+
oracleCommand
|
|
1380
|
+
.command('predict <feature>')
|
|
1381
|
+
.description('Predict feature success')
|
|
1382
|
+
.option('--description <text>', 'Feature description')
|
|
1185
1383
|
.option('--json', 'Output as JSON')
|
|
1186
|
-
.action((options) => {
|
|
1384
|
+
.action(async (feature, options) => {
|
|
1187
1385
|
try {
|
|
1188
|
-
const
|
|
1386
|
+
const result = await runModuleCommand('oracle', 'Oracle', 'oracle predict', {
|
|
1387
|
+
feature,
|
|
1388
|
+
description: options.description,
|
|
1389
|
+
_: ['predict', feature],
|
|
1390
|
+
});
|
|
1189
1391
|
if (options.json) {
|
|
1190
|
-
printJson(
|
|
1392
|
+
printJson(result);
|
|
1191
1393
|
return;
|
|
1192
1394
|
}
|
|
1193
1395
|
console.log('');
|
|
1194
|
-
console.log(theme.success('
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
}
|
|
1396
|
+
console.log(theme.success(' Oracle prediction complete.'));
|
|
1397
|
+
console.log(` ${theme.secondary('Feature:')} ${feature}`);
|
|
1398
|
+
console.log(` ${theme.secondary('Probability:')} ${result.prediction?.successProbability ?? 'n/a'}%`);
|
|
1399
|
+
console.log(` ${theme.secondary('Generated:')} ${result.prediction?.generatedAt ?? 'n/a'}`);
|
|
1198
1400
|
console.log('');
|
|
1199
1401
|
}
|
|
1200
1402
|
catch (err) {
|
|
1201
|
-
const message = err instanceof Error ? err.message : '
|
|
1403
|
+
const message = err instanceof Error ? err.message : 'Oracle prediction failed';
|
|
1202
1404
|
if (options.json) {
|
|
1203
1405
|
printJson({ status: 'error', error: message });
|
|
1204
1406
|
}
|
|
@@ -1210,219 +1412,140 @@ docsCommand
|
|
|
1210
1412
|
process.exitCode = 1;
|
|
1211
1413
|
}
|
|
1212
1414
|
});
|
|
1213
|
-
|
|
1214
|
-
.command('
|
|
1215
|
-
.description('
|
|
1415
|
+
oracleCommand
|
|
1416
|
+
.command('simulate [scenario]')
|
|
1417
|
+
.description('Run Monte Carlo simulation')
|
|
1418
|
+
.option('--iterations <count>', 'Iteration count', '10000')
|
|
1216
1419
|
.option('--json', 'Output as JSON')
|
|
1217
|
-
.action((
|
|
1218
|
-
|
|
1420
|
+
.action(async (scenario, options) => {
|
|
1421
|
+
try {
|
|
1422
|
+
const result = await runModuleCommand('oracle', 'Oracle', 'oracle simulate', {
|
|
1423
|
+
scenario: scenario || 'default',
|
|
1424
|
+
iterations: Number.parseInt(options.iterations || '10000', 10),
|
|
1425
|
+
_: ['simulate', scenario || 'default'],
|
|
1426
|
+
});
|
|
1219
1427
|
if (options.json) {
|
|
1220
|
-
printJson(
|
|
1428
|
+
printJson(result);
|
|
1221
1429
|
return;
|
|
1222
1430
|
}
|
|
1223
1431
|
console.log('');
|
|
1224
|
-
console.log(theme.
|
|
1225
|
-
console.log('');
|
|
1226
|
-
|
|
1227
|
-
console.log(` ${theme.check} ${fw.name} ${theme.dim(`— ${fw.desc}`)}`);
|
|
1228
|
-
}
|
|
1432
|
+
console.log(theme.success(' Simulation complete.'));
|
|
1433
|
+
console.log(` ${theme.secondary('Scenario:')} ${result.simulation?.scenario ?? scenario ?? 'default'}`);
|
|
1434
|
+
console.log(` ${theme.secondary('Confidence:')} ${result.simulation?.confidence ?? 'n/a'}%`);
|
|
1229
1435
|
console.log('');
|
|
1230
|
-
return;
|
|
1231
1436
|
}
|
|
1232
|
-
|
|
1233
|
-
const
|
|
1234
|
-
status: 'not_implemented',
|
|
1235
|
-
message: 'Framework auto-apply is not implemented in real runtime mode.',
|
|
1236
|
-
framework: framework || null,
|
|
1237
|
-
};
|
|
1437
|
+
catch (err) {
|
|
1438
|
+
const message = err instanceof Error ? err.message : 'Oracle simulation failed';
|
|
1238
1439
|
if (options.json) {
|
|
1239
|
-
printJson(
|
|
1440
|
+
printJson({ status: 'error', error: message });
|
|
1240
1441
|
}
|
|
1241
1442
|
else {
|
|
1242
1443
|
console.log('');
|
|
1243
|
-
console.log(theme.
|
|
1444
|
+
console.log(theme.error(` ${message}`));
|
|
1244
1445
|
console.log('');
|
|
1245
1446
|
}
|
|
1246
1447
|
process.exitCode = 1;
|
|
1247
|
-
return;
|
|
1248
|
-
}
|
|
1249
|
-
process.exitCode = 1;
|
|
1250
|
-
});
|
|
1251
|
-
program
|
|
1252
|
-
.command('dashboard')
|
|
1253
|
-
.alias('dash')
|
|
1254
|
-
.description('Show concise runtime summary')
|
|
1255
|
-
.option('--json', 'Output as JSON')
|
|
1256
|
-
.action((options) => {
|
|
1257
|
-
const cfg = getConfig().get();
|
|
1258
|
-
const stats = getContextEngine().getStats();
|
|
1259
|
-
const health = getRuntimeHealth(process.cwd());
|
|
1260
|
-
const payload = {
|
|
1261
|
-
activeProject: cfg.activeProject || null,
|
|
1262
|
-
contextFiles: stats.totalFiles,
|
|
1263
|
-
contextHealth: stats.healthScore,
|
|
1264
|
-
installedModules: cfg.installedModules.length,
|
|
1265
|
-
connectedIntegrations: health.integrations.filter(i => i.connected).length,
|
|
1266
|
-
primaryModel: health.primaryModel,
|
|
1267
|
-
};
|
|
1268
|
-
if (options.json) {
|
|
1269
|
-
printJson(payload);
|
|
1270
|
-
return;
|
|
1271
1448
|
}
|
|
1272
|
-
console.log('');
|
|
1273
|
-
console.log(box([
|
|
1274
|
-
'',
|
|
1275
|
-
` Active Project: ${payload.activeProject || 'none'}`,
|
|
1276
|
-
` Context Files: ${payload.contextFiles} (health ${payload.contextHealth}%)`,
|
|
1277
|
-
` Installed Modules: ${payload.installedModules}`,
|
|
1278
|
-
` Connected Integrations: ${payload.connectedIntegrations}`,
|
|
1279
|
-
` Primary Model: ${payload.primaryModel.provider}/${payload.primaryModel.model} (${payload.primaryModel.status})`,
|
|
1280
|
-
'',
|
|
1281
|
-
].join('\n'), 'PHANTOM DASHBOARD', 78));
|
|
1282
|
-
console.log('');
|
|
1283
1449
|
});
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
.
|
|
1288
|
-
.
|
|
1450
|
+
oracleCommand
|
|
1451
|
+
.command('forecast')
|
|
1452
|
+
.description('Generate metric forecast')
|
|
1453
|
+
.option('--metric <name>', 'Metric name', 'revenue')
|
|
1454
|
+
.option('--period <months>', 'Period in months', '6')
|
|
1455
|
+
.option('--data <json>', 'Historical data JSON array')
|
|
1289
1456
|
.option('--json', 'Output as JSON')
|
|
1290
1457
|
.action(async (options) => {
|
|
1291
1458
|
try {
|
|
1459
|
+
if (options.data) {
|
|
1460
|
+
parseJsonOption(options.data, '--data');
|
|
1461
|
+
}
|
|
1462
|
+
const result = await runModuleCommand('oracle', 'Oracle', 'oracle forecast', {
|
|
1463
|
+
metric: options.metric || 'revenue',
|
|
1464
|
+
period: Number.parseInt(options.period || '6', 10),
|
|
1465
|
+
data: options.data,
|
|
1466
|
+
_: ['forecast'],
|
|
1467
|
+
});
|
|
1292
1468
|
if (options.json) {
|
|
1293
|
-
|
|
1294
|
-
const agents = PhantomDiscovery.detectInstalledAgents();
|
|
1295
|
-
const installed = agents.filter((a) => a.installed);
|
|
1296
|
-
const results = [];
|
|
1297
|
-
for (const agent of installed) {
|
|
1298
|
-
const success = await PhantomDiscovery.registerWithAgent(agent.type);
|
|
1299
|
-
results.push({
|
|
1300
|
-
agent: agent.name,
|
|
1301
|
-
type: agent.type,
|
|
1302
|
-
success,
|
|
1303
|
-
status: success ? 'registered' : 'failed'
|
|
1304
|
-
});
|
|
1305
|
-
}
|
|
1306
|
-
printJson({
|
|
1307
|
-
timestamp: new Date().toISOString(),
|
|
1308
|
-
total_agents: installed.length,
|
|
1309
|
-
successful_registrations: results.filter(r => r.success).length,
|
|
1310
|
-
results
|
|
1311
|
-
});
|
|
1469
|
+
printJson(result);
|
|
1312
1470
|
return;
|
|
1313
1471
|
}
|
|
1314
|
-
|
|
1315
|
-
|
|
1472
|
+
console.log('');
|
|
1473
|
+
console.log(theme.success(' Forecast generated.'));
|
|
1474
|
+
console.log(` ${theme.secondary('Metric:')} ${result.forecast?.metric ?? options.metric}`);
|
|
1475
|
+
console.log(` ${theme.secondary('Confidence:')} ${result.forecast?.confidence ?? 'n/a'}%`);
|
|
1476
|
+
console.log('');
|
|
1316
1477
|
}
|
|
1317
|
-
catch (
|
|
1318
|
-
|
|
1478
|
+
catch (err) {
|
|
1479
|
+
const message = err instanceof Error ? err.message : 'Oracle forecast failed';
|
|
1480
|
+
if (options.json) {
|
|
1481
|
+
printJson({ status: 'error', error: message });
|
|
1482
|
+
}
|
|
1483
|
+
else {
|
|
1484
|
+
console.log('');
|
|
1485
|
+
console.log(theme.error(` ${message}`));
|
|
1486
|
+
console.log('');
|
|
1487
|
+
}
|
|
1319
1488
|
process.exitCode = 1;
|
|
1320
1489
|
}
|
|
1321
1490
|
});
|
|
1322
|
-
|
|
1323
|
-
.command('
|
|
1324
|
-
.description('
|
|
1491
|
+
oracleCommand
|
|
1492
|
+
.command('risk [project]')
|
|
1493
|
+
.description('Assess project risk')
|
|
1325
1494
|
.option('--json', 'Output as JSON')
|
|
1326
|
-
.action(async (options) => {
|
|
1495
|
+
.action(async (project, options) => {
|
|
1327
1496
|
try {
|
|
1497
|
+
const result = await runModuleCommand('oracle', 'Oracle', 'oracle risk', {
|
|
1498
|
+
project: project || '',
|
|
1499
|
+
_: ['risk', project || ''],
|
|
1500
|
+
});
|
|
1328
1501
|
if (options.json) {
|
|
1329
|
-
|
|
1330
|
-
const mcpRunning = await PhantomDiscovery.detectPhantom();
|
|
1331
|
-
const agents = PhantomDiscovery.detectInstalledAgents();
|
|
1332
|
-
const healthData = {
|
|
1333
|
-
timestamp: new Date().toISOString(),
|
|
1334
|
-
mcp_server: {
|
|
1335
|
-
status: mcpRunning ? 'running' : 'not_responding',
|
|
1336
|
-
version: '1.0.0'
|
|
1337
|
-
},
|
|
1338
|
-
agents: agents.map((agent) => {
|
|
1339
|
-
const configPath = PhantomDiscovery.AGENT_CONFIG_PATHS[agent.type];
|
|
1340
|
-
let registered = false;
|
|
1341
|
-
if (configPath && existsSync(configPath)) {
|
|
1342
|
-
try {
|
|
1343
|
-
const config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
1344
|
-
registered = config.mcpServers?.phantom !== undefined;
|
|
1345
|
-
}
|
|
1346
|
-
catch {
|
|
1347
|
-
registered = false;
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
return {
|
|
1351
|
-
name: agent.name,
|
|
1352
|
-
type: agent.type,
|
|
1353
|
-
installed: agent.installed,
|
|
1354
|
-
registered,
|
|
1355
|
-
status: agent.installed ? (registered ? 'connected' : 'detected_not_registered') : 'not_installed'
|
|
1356
|
-
};
|
|
1357
|
-
})
|
|
1358
|
-
};
|
|
1359
|
-
printJson(healthData);
|
|
1502
|
+
printJson(result);
|
|
1360
1503
|
return;
|
|
1361
1504
|
}
|
|
1362
|
-
|
|
1363
|
-
|
|
1505
|
+
console.log('');
|
|
1506
|
+
console.log(theme.success(' Risk assessment generated.'));
|
|
1507
|
+
console.log(` ${theme.secondary('Overall Risk:')} ${result.risk?.overallRisk ?? 'n/a'}`);
|
|
1508
|
+
console.log(` ${theme.secondary('Score:')} ${result.risk?.score ?? 'n/a'}`);
|
|
1509
|
+
console.log('');
|
|
1364
1510
|
}
|
|
1365
|
-
catch (
|
|
1366
|
-
|
|
1511
|
+
catch (err) {
|
|
1512
|
+
const message = err instanceof Error ? err.message : 'Oracle risk assessment failed';
|
|
1513
|
+
if (options.json) {
|
|
1514
|
+
printJson({ status: 'error', error: message });
|
|
1515
|
+
}
|
|
1516
|
+
else {
|
|
1517
|
+
console.log('');
|
|
1518
|
+
console.log(theme.error(` ${message}`));
|
|
1519
|
+
console.log('');
|
|
1520
|
+
}
|
|
1367
1521
|
process.exitCode = 1;
|
|
1368
1522
|
}
|
|
1369
1523
|
});
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
.
|
|
1373
|
-
.
|
|
1524
|
+
const experimentCommand = program.command('experiment').description('A/B test and experimentation workflow');
|
|
1525
|
+
experimentCommand
|
|
1526
|
+
.command('design <hypothesis>')
|
|
1527
|
+
.description('Design an experiment')
|
|
1528
|
+
.option('--metric <name>', 'Primary metric', 'conversion_rate')
|
|
1374
1529
|
.option('--json', 'Output as JSON')
|
|
1375
|
-
.action(async (options) => {
|
|
1530
|
+
.action(async (hypothesis, options) => {
|
|
1376
1531
|
try {
|
|
1377
|
-
const
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
printJson({ detected: agents, registered: registered.map(r => r.id) });
|
|
1385
|
-
return;
|
|
1386
|
-
}
|
|
1387
|
-
console.log('');
|
|
1388
|
-
console.log(theme.success(` Registered ${registered.length} new agents:`));
|
|
1389
|
-
for (const agent of registered) {
|
|
1390
|
-
console.log(` • ${agent.signature.name}`);
|
|
1391
|
-
}
|
|
1392
|
-
console.log('');
|
|
1393
|
-
}
|
|
1394
|
-
if (options.json && !options.register) {
|
|
1395
|
-
printJson({ agents });
|
|
1532
|
+
const result = await runModuleCommand('experiment-lab', 'Experiment Lab', 'experiment design', {
|
|
1533
|
+
hypothesis,
|
|
1534
|
+
metric: options.metric || 'conversion_rate',
|
|
1535
|
+
_: ['design', hypothesis],
|
|
1536
|
+
});
|
|
1537
|
+
if (options.json) {
|
|
1538
|
+
printJson(result);
|
|
1396
1539
|
return;
|
|
1397
1540
|
}
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
console.log(theme.warning(' No AI agents detected in your system.'));
|
|
1404
|
-
console.log(theme.dim(' Supported: Claude Code, Cursor, Codex, Gemini, ChatGPT, VS Code, Zed'));
|
|
1405
|
-
console.log('');
|
|
1406
|
-
return;
|
|
1407
|
-
}
|
|
1408
|
-
for (const agent of agents) {
|
|
1409
|
-
const statusIcon = agent.status === 'running' ? '🟢' : '🔵';
|
|
1410
|
-
const confidenceColor = agent.confidence > 80 ? theme.success :
|
|
1411
|
-
agent.confidence > 60 ? theme.warning : theme.dim;
|
|
1412
|
-
console.log(` ${statusIcon} ${theme.accent(agent.signature.name)}`);
|
|
1413
|
-
console.log(` ${theme.secondary(agent.signature.description)}`);
|
|
1414
|
-
console.log(` ${confidenceColor(`Confidence: ${agent.confidence}%`)} | Status: ${agent.status}`);
|
|
1415
|
-
if (agent.detectedPaths.length > 0) {
|
|
1416
|
-
console.log(` ${theme.dim(`Paths: ${agent.detectedPaths.join(', ')}`)}`);
|
|
1417
|
-
}
|
|
1418
|
-
console.log('');
|
|
1419
|
-
}
|
|
1420
|
-
console.log(theme.dim(' Run with --register to automatically register detected agents'));
|
|
1421
|
-
console.log('');
|
|
1422
|
-
}
|
|
1541
|
+
console.log('');
|
|
1542
|
+
console.log(theme.success(' Experiment design created.'));
|
|
1543
|
+
console.log(` ${theme.secondary('Experiment:')} ${result.experiment?.name ?? 'n/a'}`);
|
|
1544
|
+
console.log(` ${theme.secondary('Sample Size:')} ${result.experiment?.sampleSize ?? 'n/a'}`);
|
|
1545
|
+
console.log('');
|
|
1423
1546
|
}
|
|
1424
1547
|
catch (err) {
|
|
1425
|
-
const message = err instanceof Error ? err.message : '
|
|
1548
|
+
const message = err instanceof Error ? err.message : 'Experiment design failed';
|
|
1426
1549
|
if (options.json) {
|
|
1427
1550
|
printJson({ status: 'error', error: message });
|
|
1428
1551
|
}
|
|
@@ -1434,25 +1557,811 @@ agentsCommand
|
|
|
1434
1557
|
process.exitCode = 1;
|
|
1435
1558
|
}
|
|
1436
1559
|
});
|
|
1437
|
-
|
|
1438
|
-
.command('
|
|
1439
|
-
.description('
|
|
1560
|
+
experimentCommand
|
|
1561
|
+
.command('analyze <experimentId>')
|
|
1562
|
+
.description('Analyze experiment results')
|
|
1563
|
+
.option('--data <json>', 'Variant data JSON object')
|
|
1440
1564
|
.option('--json', 'Output as JSON')
|
|
1441
|
-
.action(async (options) => {
|
|
1565
|
+
.action(async (experimentId, options) => {
|
|
1442
1566
|
try {
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1567
|
+
if (options.data) {
|
|
1568
|
+
parseJsonOption(options.data, '--data');
|
|
1569
|
+
}
|
|
1570
|
+
const result = await runModuleCommand('experiment-lab', 'Experiment Lab', 'experiment analyze', {
|
|
1571
|
+
experimentId,
|
|
1572
|
+
data: options.data,
|
|
1573
|
+
_: ['analyze', experimentId],
|
|
1574
|
+
});
|
|
1446
1575
|
if (options.json) {
|
|
1447
|
-
printJson(
|
|
1576
|
+
printJson(result);
|
|
1448
1577
|
return;
|
|
1449
1578
|
}
|
|
1450
1579
|
console.log('');
|
|
1451
|
-
console.log(theme.
|
|
1580
|
+
console.log(theme.success(' Experiment analysis complete.'));
|
|
1581
|
+
console.log(` ${theme.secondary('Winner:')} ${result.analysis?.winner ?? 'n/a'}`);
|
|
1582
|
+
console.log(` ${theme.secondary('Significant:')} ${result.analysis?.statisticalSignificance ?? 'n/a'}`);
|
|
1452
1583
|
console.log('');
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1584
|
+
}
|
|
1585
|
+
catch (err) {
|
|
1586
|
+
const message = err instanceof Error ? err.message : 'Experiment analysis failed';
|
|
1587
|
+
if (options.json) {
|
|
1588
|
+
printJson({ status: 'error', error: message });
|
|
1589
|
+
}
|
|
1590
|
+
else {
|
|
1591
|
+
console.log('');
|
|
1592
|
+
console.log(theme.error(` ${message}`));
|
|
1593
|
+
console.log('');
|
|
1594
|
+
}
|
|
1595
|
+
process.exitCode = 1;
|
|
1596
|
+
}
|
|
1597
|
+
});
|
|
1598
|
+
experimentCommand
|
|
1599
|
+
.command('sample-size')
|
|
1600
|
+
.description('Calculate required sample size')
|
|
1601
|
+
.option('--baseline <rate>', 'Baseline conversion rate', '0.2')
|
|
1602
|
+
.option('--mde <rate>', 'Minimum detectable effect', '0.05')
|
|
1603
|
+
.option('--confidence <rate>', 'Confidence level', '0.95')
|
|
1604
|
+
.option('--power <rate>', 'Statistical power', '0.8')
|
|
1605
|
+
.option('--json', 'Output as JSON')
|
|
1606
|
+
.action(async (options) => {
|
|
1607
|
+
try {
|
|
1608
|
+
const result = await runModuleCommand('experiment-lab', 'Experiment Lab', 'experiment sample-size', {
|
|
1609
|
+
baseline: Number.parseFloat(options.baseline || '0.2'),
|
|
1610
|
+
mde: Number.parseFloat(options.mde || '0.05'),
|
|
1611
|
+
confidence: Number.parseFloat(options.confidence || '0.95'),
|
|
1612
|
+
power: Number.parseFloat(options.power || '0.8'),
|
|
1613
|
+
_: ['sample-size'],
|
|
1614
|
+
});
|
|
1615
|
+
if (options.json) {
|
|
1616
|
+
printJson(result);
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
console.log('');
|
|
1620
|
+
console.log(theme.success(' Sample size calculation complete.'));
|
|
1621
|
+
console.log(` ${theme.secondary('Sample Size:')} ${result.calculation?.sampleSize ?? 'n/a'}`);
|
|
1622
|
+
console.log(` ${theme.secondary('Duration (days):')} ${result.calculation?.duration ?? 'n/a'}`);
|
|
1623
|
+
console.log('');
|
|
1624
|
+
}
|
|
1625
|
+
catch (err) {
|
|
1626
|
+
const message = err instanceof Error ? err.message : 'Sample size calculation failed';
|
|
1627
|
+
if (options.json) {
|
|
1628
|
+
printJson({ status: 'error', error: message });
|
|
1629
|
+
}
|
|
1630
|
+
else {
|
|
1631
|
+
console.log('');
|
|
1632
|
+
console.log(theme.error(` ${message}`));
|
|
1633
|
+
console.log('');
|
|
1634
|
+
}
|
|
1635
|
+
process.exitCode = 1;
|
|
1636
|
+
}
|
|
1637
|
+
});
|
|
1638
|
+
experimentCommand
|
|
1639
|
+
.command('rollout <experimentId>')
|
|
1640
|
+
.description('Create rollout strategy')
|
|
1641
|
+
.option('--phases <count>', 'Rollout phases', '3')
|
|
1642
|
+
.option('--json', 'Output as JSON')
|
|
1643
|
+
.action(async (experimentId, options) => {
|
|
1644
|
+
try {
|
|
1645
|
+
const result = await runModuleCommand('experiment-lab', 'Experiment Lab', 'experiment rollout', {
|
|
1646
|
+
experimentId,
|
|
1647
|
+
phases: Number.parseInt(options.phases || '3', 10),
|
|
1648
|
+
_: ['rollout', experimentId],
|
|
1649
|
+
});
|
|
1650
|
+
if (options.json) {
|
|
1651
|
+
printJson(result);
|
|
1652
|
+
return;
|
|
1653
|
+
}
|
|
1654
|
+
console.log('');
|
|
1655
|
+
console.log(theme.success(' Rollout strategy created.'));
|
|
1656
|
+
console.log(` ${theme.secondary('Phases:')} ${result.strategy?.phases?.length ?? 'n/a'}`);
|
|
1657
|
+
console.log(` ${theme.secondary('Risk Level:')} ${result.strategy?.riskLevel ?? 'n/a'}`);
|
|
1658
|
+
console.log('');
|
|
1659
|
+
}
|
|
1660
|
+
catch (err) {
|
|
1661
|
+
const message = err instanceof Error ? err.message : 'Rollout strategy failed';
|
|
1662
|
+
if (options.json) {
|
|
1663
|
+
printJson({ status: 'error', error: message });
|
|
1664
|
+
}
|
|
1665
|
+
else {
|
|
1666
|
+
console.log('');
|
|
1667
|
+
console.log(theme.error(` ${message}`));
|
|
1668
|
+
console.log('');
|
|
1669
|
+
}
|
|
1670
|
+
process.exitCode = 1;
|
|
1671
|
+
}
|
|
1672
|
+
});
|
|
1673
|
+
const uxCommand = program.command('ux').description('UX auditing and WCAG checks');
|
|
1674
|
+
uxCommand
|
|
1675
|
+
.command('audit <imagePath>')
|
|
1676
|
+
.description('Audit a UI screenshot')
|
|
1677
|
+
.option('--page-type <type>', 'Page type', 'generic')
|
|
1678
|
+
.option('--no-wcag', 'Skip WCAG checks')
|
|
1679
|
+
.option('--json', 'Output as JSON')
|
|
1680
|
+
.action(async (imagePath, options) => {
|
|
1681
|
+
try {
|
|
1682
|
+
const result = await runModuleCommand('ux-auditor', 'UX Auditor', 'ux audit', {
|
|
1683
|
+
imagePath,
|
|
1684
|
+
pageType: options.pageType || 'generic',
|
|
1685
|
+
wcag: options.wcag !== false,
|
|
1686
|
+
_: ['audit', imagePath],
|
|
1687
|
+
});
|
|
1688
|
+
if (options.json) {
|
|
1689
|
+
printJson(result);
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
console.log('');
|
|
1693
|
+
console.log(theme.success(' UX audit complete.'));
|
|
1694
|
+
console.log(` ${theme.secondary('Score:')} ${result.audit?.overallScore ?? 'n/a'}`);
|
|
1695
|
+
console.log(` ${theme.secondary('Issues:')} ${result.audit?.issues?.length ?? 'n/a'}`);
|
|
1696
|
+
console.log('');
|
|
1697
|
+
}
|
|
1698
|
+
catch (err) {
|
|
1699
|
+
const message = err instanceof Error ? err.message : 'UX audit failed';
|
|
1700
|
+
if (options.json) {
|
|
1701
|
+
printJson({ status: 'error', error: message });
|
|
1702
|
+
}
|
|
1703
|
+
else {
|
|
1704
|
+
console.log('');
|
|
1705
|
+
console.log(theme.error(` ${message}`));
|
|
1706
|
+
console.log('');
|
|
1707
|
+
}
|
|
1708
|
+
process.exitCode = 1;
|
|
1709
|
+
}
|
|
1710
|
+
});
|
|
1711
|
+
uxCommand
|
|
1712
|
+
.command('score <imagePath>')
|
|
1713
|
+
.description('Get quick UX score')
|
|
1714
|
+
.option('--json', 'Output as JSON')
|
|
1715
|
+
.action(async (imagePath, options) => {
|
|
1716
|
+
try {
|
|
1717
|
+
const result = await runModuleCommand('ux-auditor', 'UX Auditor', 'ux score', {
|
|
1718
|
+
imagePath,
|
|
1719
|
+
_: ['score', imagePath],
|
|
1720
|
+
});
|
|
1721
|
+
if (options.json) {
|
|
1722
|
+
printJson(result);
|
|
1723
|
+
return;
|
|
1724
|
+
}
|
|
1725
|
+
console.log('');
|
|
1726
|
+
console.log(theme.success(' UX score generated.'));
|
|
1727
|
+
console.log(` ${theme.secondary('Overall:')} ${result.scores?.overall ?? 'n/a'}`);
|
|
1728
|
+
console.log('');
|
|
1729
|
+
}
|
|
1730
|
+
catch (err) {
|
|
1731
|
+
const message = err instanceof Error ? err.message : 'UX score failed';
|
|
1732
|
+
if (options.json) {
|
|
1733
|
+
printJson({ status: 'error', error: message });
|
|
1734
|
+
}
|
|
1735
|
+
else {
|
|
1736
|
+
console.log('');
|
|
1737
|
+
console.log(theme.error(` ${message}`));
|
|
1738
|
+
console.log('');
|
|
1739
|
+
}
|
|
1740
|
+
process.exitCode = 1;
|
|
1741
|
+
}
|
|
1742
|
+
});
|
|
1743
|
+
uxCommand
|
|
1744
|
+
.command('compare <before> <after>')
|
|
1745
|
+
.description('Compare UX between two screenshots')
|
|
1746
|
+
.option('--json', 'Output as JSON')
|
|
1747
|
+
.action(async (before, after, options) => {
|
|
1748
|
+
try {
|
|
1749
|
+
const result = await runModuleCommand('ux-auditor', 'UX Auditor', 'ux compare', {
|
|
1750
|
+
before,
|
|
1751
|
+
after,
|
|
1752
|
+
_: ['compare', before, after],
|
|
1753
|
+
});
|
|
1754
|
+
if (options.json) {
|
|
1755
|
+
printJson(result);
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1758
|
+
console.log('');
|
|
1759
|
+
console.log(theme.success(' UX comparison complete.'));
|
|
1760
|
+
console.log(` ${theme.secondary('Delta:')} ${result.comparison?.scoreDifference ?? 'n/a'}`);
|
|
1761
|
+
console.log('');
|
|
1762
|
+
}
|
|
1763
|
+
catch (err) {
|
|
1764
|
+
const message = err instanceof Error ? err.message : 'UX comparison failed';
|
|
1765
|
+
if (options.json) {
|
|
1766
|
+
printJson({ status: 'error', error: message });
|
|
1767
|
+
}
|
|
1768
|
+
else {
|
|
1769
|
+
console.log('');
|
|
1770
|
+
console.log(theme.error(` ${message}`));
|
|
1771
|
+
console.log('');
|
|
1772
|
+
}
|
|
1773
|
+
process.exitCode = 1;
|
|
1774
|
+
}
|
|
1775
|
+
});
|
|
1776
|
+
uxCommand
|
|
1777
|
+
.command('wcag <imagePath>')
|
|
1778
|
+
.description('Generate WCAG compliance report')
|
|
1779
|
+
.option('--level <level>', 'WCAG level (A|AA|AAA)', 'AA')
|
|
1780
|
+
.option('--json', 'Output as JSON')
|
|
1781
|
+
.action(async (imagePath, options) => {
|
|
1782
|
+
try {
|
|
1783
|
+
const result = await runModuleCommand('ux-auditor', 'UX Auditor', 'ux wcag', {
|
|
1784
|
+
imagePath,
|
|
1785
|
+
level: options.level || 'AA',
|
|
1786
|
+
_: ['wcag', imagePath],
|
|
1787
|
+
});
|
|
1788
|
+
if (options.json) {
|
|
1789
|
+
printJson(result);
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
console.log('');
|
|
1793
|
+
console.log(theme.success(' WCAG report generated.'));
|
|
1794
|
+
console.log(` ${theme.secondary('Level:')} ${result.wcag?.level ?? options.level}`);
|
|
1795
|
+
console.log(` ${theme.secondary('Score:')} ${result.wcag?.score ?? 'n/a'}`);
|
|
1796
|
+
console.log('');
|
|
1797
|
+
}
|
|
1798
|
+
catch (err) {
|
|
1799
|
+
const message = err instanceof Error ? err.message : 'WCAG report failed';
|
|
1800
|
+
if (options.json) {
|
|
1801
|
+
printJson({ status: 'error', error: message });
|
|
1802
|
+
}
|
|
1803
|
+
else {
|
|
1804
|
+
console.log('');
|
|
1805
|
+
console.log(theme.error(` ${message}`));
|
|
1806
|
+
console.log('');
|
|
1807
|
+
}
|
|
1808
|
+
process.exitCode = 1;
|
|
1809
|
+
}
|
|
1810
|
+
});
|
|
1811
|
+
const timeMachineCommand = program.command('timemachine').description('Decision snapshots and what-if analysis');
|
|
1812
|
+
timeMachineCommand
|
|
1813
|
+
.command('snapshot')
|
|
1814
|
+
.description('Create a product snapshot')
|
|
1815
|
+
.option('--name <name>', 'Snapshot name')
|
|
1816
|
+
.option('--description <text>', 'Snapshot description')
|
|
1817
|
+
.option('--tags <csv>', 'Comma-separated tags')
|
|
1818
|
+
.option('--json', 'Output as JSON')
|
|
1819
|
+
.action(async (options) => {
|
|
1820
|
+
try {
|
|
1821
|
+
const result = await runModuleCommand('time-machine', 'Time Machine', 'timemachine snapshot', {
|
|
1822
|
+
name: options.name,
|
|
1823
|
+
description: options.description,
|
|
1824
|
+
tags: options.tags,
|
|
1825
|
+
_: ['snapshot'],
|
|
1826
|
+
});
|
|
1827
|
+
if (options.json) {
|
|
1828
|
+
printJson(result);
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
console.log('');
|
|
1832
|
+
console.log(theme.success(' Snapshot created.'));
|
|
1833
|
+
console.log(` ${theme.secondary('Snapshot ID:')} ${result.snapshot?.id ?? 'n/a'}`);
|
|
1834
|
+
console.log(` ${theme.secondary('Name:')} ${result.snapshot?.name ?? 'n/a'}`);
|
|
1835
|
+
console.log('');
|
|
1836
|
+
}
|
|
1837
|
+
catch (err) {
|
|
1838
|
+
const message = err instanceof Error ? err.message : 'Snapshot creation failed';
|
|
1839
|
+
if (options.json) {
|
|
1840
|
+
printJson({ status: 'error', error: message });
|
|
1841
|
+
}
|
|
1842
|
+
else {
|
|
1843
|
+
console.log('');
|
|
1844
|
+
console.log(theme.error(` ${message}`));
|
|
1845
|
+
console.log('');
|
|
1846
|
+
}
|
|
1847
|
+
process.exitCode = 1;
|
|
1848
|
+
}
|
|
1849
|
+
});
|
|
1850
|
+
timeMachineCommand
|
|
1851
|
+
.command('compare <id1> <id2>')
|
|
1852
|
+
.description('Compare two snapshots')
|
|
1853
|
+
.option('--json', 'Output as JSON')
|
|
1854
|
+
.action(async (id1, id2, options) => {
|
|
1855
|
+
try {
|
|
1856
|
+
const result = await runModuleCommand('time-machine', 'Time Machine', 'timemachine compare', {
|
|
1857
|
+
id1,
|
|
1858
|
+
id2,
|
|
1859
|
+
_: ['compare', id1, id2],
|
|
1860
|
+
});
|
|
1861
|
+
if (options.json) {
|
|
1862
|
+
printJson(result);
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
console.log('');
|
|
1866
|
+
console.log(theme.success(' Snapshot comparison complete.'));
|
|
1867
|
+
console.log(` ${theme.secondary('Added Decisions:')} ${result.comparison?.addedDecisions?.length ?? 'n/a'}`);
|
|
1868
|
+
console.log(` ${theme.secondary('Changed Decisions:')} ${result.comparison?.changedDecisions?.length ?? 'n/a'}`);
|
|
1869
|
+
console.log('');
|
|
1870
|
+
}
|
|
1871
|
+
catch (err) {
|
|
1872
|
+
const message = err instanceof Error ? err.message : 'Snapshot comparison failed';
|
|
1873
|
+
if (options.json) {
|
|
1874
|
+
printJson({ status: 'error', error: message });
|
|
1875
|
+
}
|
|
1876
|
+
else {
|
|
1877
|
+
console.log('');
|
|
1878
|
+
console.log(theme.error(` ${message}`));
|
|
1879
|
+
console.log('');
|
|
1880
|
+
}
|
|
1881
|
+
process.exitCode = 1;
|
|
1882
|
+
}
|
|
1883
|
+
});
|
|
1884
|
+
timeMachineCommand
|
|
1885
|
+
.command('list')
|
|
1886
|
+
.description('List saved snapshots')
|
|
1887
|
+
.option('--json', 'Output as JSON')
|
|
1888
|
+
.action(async (options) => {
|
|
1889
|
+
try {
|
|
1890
|
+
const result = await runModuleCommand('time-machine', 'Time Machine', 'timemachine list', {
|
|
1891
|
+
_: ['list'],
|
|
1892
|
+
});
|
|
1893
|
+
if (options.json) {
|
|
1894
|
+
printJson(result);
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1897
|
+
console.log('');
|
|
1898
|
+
console.log(theme.success(' Snapshots loaded.'));
|
|
1899
|
+
console.log(` ${theme.secondary('Count:')} ${result.count ?? 0}`);
|
|
1900
|
+
console.log('');
|
|
1901
|
+
}
|
|
1902
|
+
catch (err) {
|
|
1903
|
+
const message = err instanceof Error ? err.message : 'Snapshot list failed';
|
|
1904
|
+
if (options.json) {
|
|
1905
|
+
printJson({ status: 'error', error: message });
|
|
1906
|
+
}
|
|
1907
|
+
else {
|
|
1908
|
+
console.log('');
|
|
1909
|
+
console.log(theme.error(` ${message}`));
|
|
1910
|
+
console.log('');
|
|
1911
|
+
}
|
|
1912
|
+
process.exitCode = 1;
|
|
1913
|
+
}
|
|
1914
|
+
});
|
|
1915
|
+
timeMachineCommand
|
|
1916
|
+
.command('whatif <baseId>')
|
|
1917
|
+
.description('Create a what-if scenario')
|
|
1918
|
+
.option('--name <name>', 'Scenario name')
|
|
1919
|
+
.option('--decision <json>', 'Decision JSON payload')
|
|
1920
|
+
.option('--json', 'Output as JSON')
|
|
1921
|
+
.action(async (baseId, options) => {
|
|
1922
|
+
try {
|
|
1923
|
+
const decision = parseJsonOption(options.decision, '--decision');
|
|
1924
|
+
const result = await runModuleCommand('time-machine', 'Time Machine', 'timemachine whatif', {
|
|
1925
|
+
baseId,
|
|
1926
|
+
name: options.name,
|
|
1927
|
+
decision,
|
|
1928
|
+
_: ['whatif', baseId],
|
|
1929
|
+
});
|
|
1930
|
+
if (options.json) {
|
|
1931
|
+
printJson(result);
|
|
1932
|
+
return;
|
|
1933
|
+
}
|
|
1934
|
+
console.log('');
|
|
1935
|
+
console.log(theme.success(' What-if scenario created.'));
|
|
1936
|
+
console.log(` ${theme.secondary('Scenario ID:')} ${result.scenario?.id ?? 'n/a'}`);
|
|
1937
|
+
console.log(` ${theme.secondary('Risk:')} ${result.scenario?.riskAssessment?.overallRisk ?? 'n/a'}`);
|
|
1938
|
+
console.log('');
|
|
1939
|
+
}
|
|
1940
|
+
catch (err) {
|
|
1941
|
+
const message = err instanceof Error ? err.message : 'What-if scenario failed';
|
|
1942
|
+
if (options.json) {
|
|
1943
|
+
printJson({ status: 'error', error: message });
|
|
1944
|
+
}
|
|
1945
|
+
else {
|
|
1946
|
+
console.log('');
|
|
1947
|
+
console.log(theme.error(` ${message}`));
|
|
1948
|
+
console.log('');
|
|
1949
|
+
}
|
|
1950
|
+
process.exitCode = 1;
|
|
1951
|
+
}
|
|
1952
|
+
});
|
|
1953
|
+
const figmaCommand = program.command('figma').description('Figma integration and design analysis');
|
|
1954
|
+
figmaCommand
|
|
1955
|
+
.command('sync <fileKey>')
|
|
1956
|
+
.description('Sync a Figma file')
|
|
1957
|
+
.option('--json', 'Output as JSON')
|
|
1958
|
+
.action(async (fileKey, options) => {
|
|
1959
|
+
try {
|
|
1960
|
+
const result = await runModuleCommand('figma-bridge', 'Figma Bridge', 'figma sync', {
|
|
1961
|
+
fileKey,
|
|
1962
|
+
_: ['sync', fileKey],
|
|
1963
|
+
});
|
|
1964
|
+
if (options.json) {
|
|
1965
|
+
printJson(result);
|
|
1966
|
+
return;
|
|
1967
|
+
}
|
|
1968
|
+
console.log('');
|
|
1969
|
+
console.log(theme.success(' Figma sync complete.'));
|
|
1970
|
+
console.log(` ${theme.secondary('Pages Synced:')} ${result.sync?.pagesSynced ?? 'n/a'}`);
|
|
1971
|
+
console.log('');
|
|
1972
|
+
}
|
|
1973
|
+
catch (err) {
|
|
1974
|
+
const message = err instanceof Error ? err.message : 'Figma sync failed';
|
|
1975
|
+
if (options.json) {
|
|
1976
|
+
printJson({ status: 'error', error: message });
|
|
1977
|
+
}
|
|
1978
|
+
else {
|
|
1979
|
+
console.log('');
|
|
1980
|
+
console.log(theme.error(` ${message}`));
|
|
1981
|
+
console.log('');
|
|
1982
|
+
}
|
|
1983
|
+
process.exitCode = 1;
|
|
1984
|
+
}
|
|
1985
|
+
});
|
|
1986
|
+
figmaCommand
|
|
1987
|
+
.command('analyze <fileKey>')
|
|
1988
|
+
.description('Analyze a Figma design')
|
|
1989
|
+
.option('--json', 'Output as JSON')
|
|
1990
|
+
.action(async (fileKey, options) => {
|
|
1991
|
+
try {
|
|
1992
|
+
const result = await runModuleCommand('figma-bridge', 'Figma Bridge', 'figma analyze', {
|
|
1993
|
+
fileKey,
|
|
1994
|
+
_: ['analyze', fileKey],
|
|
1995
|
+
});
|
|
1996
|
+
if (options.json) {
|
|
1997
|
+
printJson(result);
|
|
1998
|
+
return;
|
|
1999
|
+
}
|
|
2000
|
+
console.log('');
|
|
2001
|
+
console.log(theme.success(' Figma design analysis complete.'));
|
|
2002
|
+
console.log(` ${theme.secondary('Screens:')} ${result.analysis?.screens?.length ?? 'n/a'}`);
|
|
2003
|
+
console.log(` ${theme.secondary('Components:')} ${result.analysis?.components?.length ?? 'n/a'}`);
|
|
2004
|
+
console.log('');
|
|
2005
|
+
}
|
|
2006
|
+
catch (err) {
|
|
2007
|
+
const message = err instanceof Error ? err.message : 'Figma analysis failed';
|
|
2008
|
+
if (options.json) {
|
|
2009
|
+
printJson({ status: 'error', error: message });
|
|
2010
|
+
}
|
|
2011
|
+
else {
|
|
2012
|
+
console.log('');
|
|
2013
|
+
console.log(theme.error(` ${message}`));
|
|
2014
|
+
console.log('');
|
|
2015
|
+
}
|
|
2016
|
+
process.exitCode = 1;
|
|
2017
|
+
}
|
|
2018
|
+
});
|
|
2019
|
+
figmaCommand
|
|
2020
|
+
.command('stories <fileKey>')
|
|
2021
|
+
.description('Generate stories from Figma design')
|
|
2022
|
+
.option('--json', 'Output as JSON')
|
|
2023
|
+
.action(async (fileKey, options) => {
|
|
2024
|
+
try {
|
|
2025
|
+
const result = await runModuleCommand('figma-bridge', 'Figma Bridge', 'figma stories', {
|
|
2026
|
+
fileKey,
|
|
2027
|
+
_: ['stories', fileKey],
|
|
2028
|
+
});
|
|
2029
|
+
if (options.json) {
|
|
2030
|
+
printJson(result);
|
|
2031
|
+
return;
|
|
2032
|
+
}
|
|
2033
|
+
console.log('');
|
|
2034
|
+
console.log(theme.success(' Stories generated from Figma.'));
|
|
2035
|
+
console.log(` ${theme.secondary('Count:')} ${result.count ?? 0}`);
|
|
2036
|
+
console.log('');
|
|
2037
|
+
}
|
|
2038
|
+
catch (err) {
|
|
2039
|
+
const message = err instanceof Error ? err.message : 'Figma story generation failed';
|
|
2040
|
+
if (options.json) {
|
|
2041
|
+
printJson({ status: 'error', error: message });
|
|
2042
|
+
}
|
|
2043
|
+
else {
|
|
2044
|
+
console.log('');
|
|
2045
|
+
console.log(theme.error(` ${message}`));
|
|
2046
|
+
console.log('');
|
|
2047
|
+
}
|
|
2048
|
+
process.exitCode = 1;
|
|
2049
|
+
}
|
|
2050
|
+
});
|
|
2051
|
+
figmaCommand
|
|
2052
|
+
.command('prd <fileKey>')
|
|
2053
|
+
.description('Generate PRD from Figma design')
|
|
2054
|
+
.option('--title <name>', 'PRD title')
|
|
2055
|
+
.option('--json', 'Output as JSON')
|
|
2056
|
+
.action(async (fileKey, options) => {
|
|
2057
|
+
try {
|
|
2058
|
+
const result = await runModuleCommand('figma-bridge', 'Figma Bridge', 'figma prd', {
|
|
2059
|
+
fileKey,
|
|
2060
|
+
title: options.title,
|
|
2061
|
+
_: ['prd', fileKey],
|
|
2062
|
+
});
|
|
2063
|
+
if (options.json) {
|
|
2064
|
+
printJson(result);
|
|
2065
|
+
return;
|
|
2066
|
+
}
|
|
2067
|
+
console.log('');
|
|
2068
|
+
console.log(theme.success(' PRD generated from Figma.'));
|
|
2069
|
+
console.log(` ${theme.secondary('PRD ID:')} ${result.prd?.id ?? 'n/a'}`);
|
|
2070
|
+
console.log('');
|
|
2071
|
+
}
|
|
2072
|
+
catch (err) {
|
|
2073
|
+
const message = err instanceof Error ? err.message : 'Figma PRD generation failed';
|
|
2074
|
+
if (options.json) {
|
|
2075
|
+
printJson({ status: 'error', error: message });
|
|
2076
|
+
}
|
|
2077
|
+
else {
|
|
2078
|
+
console.log('');
|
|
2079
|
+
console.log(theme.error(` ${message}`));
|
|
2080
|
+
console.log('');
|
|
2081
|
+
}
|
|
2082
|
+
process.exitCode = 1;
|
|
2083
|
+
}
|
|
2084
|
+
});
|
|
2085
|
+
figmaCommand
|
|
2086
|
+
.command('list')
|
|
2087
|
+
.description('List cached Figma files')
|
|
2088
|
+
.option('--json', 'Output as JSON')
|
|
2089
|
+
.action(async (options) => {
|
|
2090
|
+
try {
|
|
2091
|
+
const result = await runModuleCommand('figma-bridge', 'Figma Bridge', 'figma list', {
|
|
2092
|
+
_: ['list'],
|
|
2093
|
+
});
|
|
2094
|
+
if (options.json) {
|
|
2095
|
+
printJson(result);
|
|
2096
|
+
return;
|
|
2097
|
+
}
|
|
2098
|
+
console.log('');
|
|
2099
|
+
console.log(theme.success(' Cached Figma files loaded.'));
|
|
2100
|
+
console.log(` ${theme.secondary('Count:')} ${result.count ?? 0}`);
|
|
2101
|
+
console.log('');
|
|
2102
|
+
}
|
|
2103
|
+
catch (err) {
|
|
2104
|
+
const message = err instanceof Error ? err.message : 'Figma file list failed';
|
|
2105
|
+
if (options.json) {
|
|
2106
|
+
printJson({ status: 'error', error: message });
|
|
2107
|
+
}
|
|
2108
|
+
else {
|
|
2109
|
+
console.log('');
|
|
2110
|
+
console.log(theme.error(` ${message}`));
|
|
2111
|
+
console.log('');
|
|
2112
|
+
}
|
|
2113
|
+
process.exitCode = 1;
|
|
2114
|
+
}
|
|
2115
|
+
});
|
|
2116
|
+
docsCommand
|
|
2117
|
+
.command('generate')
|
|
2118
|
+
.description('Generate deterministic documentation artifacts')
|
|
2119
|
+
.option('--out <path>', 'Output directory path')
|
|
2120
|
+
.option('--json', 'Output as JSON')
|
|
2121
|
+
.action((options) => {
|
|
2122
|
+
try {
|
|
2123
|
+
const files = generateRealDocumentation(process.cwd(), options.out);
|
|
2124
|
+
if (options.json) {
|
|
2125
|
+
printJson({ files });
|
|
2126
|
+
return;
|
|
2127
|
+
}
|
|
2128
|
+
console.log('');
|
|
2129
|
+
console.log(theme.success(' Documentation generated:'));
|
|
2130
|
+
for (const file of files) {
|
|
2131
|
+
console.log(` ${theme.check} ${file}`);
|
|
2132
|
+
}
|
|
2133
|
+
console.log('');
|
|
2134
|
+
}
|
|
2135
|
+
catch (err) {
|
|
2136
|
+
const message = err instanceof Error ? err.message : 'Documentation generation failed';
|
|
2137
|
+
if (options.json) {
|
|
2138
|
+
printJson({ status: 'error', error: message });
|
|
2139
|
+
}
|
|
2140
|
+
else {
|
|
2141
|
+
console.log('');
|
|
2142
|
+
console.log(theme.error(` ${message}`));
|
|
2143
|
+
console.log('');
|
|
2144
|
+
}
|
|
2145
|
+
process.exitCode = 1;
|
|
2146
|
+
}
|
|
2147
|
+
});
|
|
2148
|
+
program
|
|
2149
|
+
.command('frameworks [action] [framework]')
|
|
2150
|
+
.description('List built-in PM frameworks')
|
|
2151
|
+
.option('--json', 'Output as JSON')
|
|
2152
|
+
.action((action, framework, options) => {
|
|
2153
|
+
if (!action || action === 'list') {
|
|
2154
|
+
if (options.json) {
|
|
2155
|
+
printJson({ frameworks: FRAMEWORKS });
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2158
|
+
console.log('');
|
|
2159
|
+
console.log(theme.title(' PM FRAMEWORKS'));
|
|
2160
|
+
console.log('');
|
|
2161
|
+
for (const fw of FRAMEWORKS) {
|
|
2162
|
+
console.log(` ${theme.check} ${fw.name} ${theme.dim(`— ${fw.desc}`)}`);
|
|
2163
|
+
}
|
|
2164
|
+
console.log('');
|
|
2165
|
+
return;
|
|
2166
|
+
}
|
|
2167
|
+
if (action === 'apply') {
|
|
2168
|
+
const payload = {
|
|
2169
|
+
status: 'not_implemented',
|
|
2170
|
+
message: 'Framework auto-apply is not implemented in real runtime mode.',
|
|
2171
|
+
framework: framework || null,
|
|
2172
|
+
};
|
|
2173
|
+
if (options.json) {
|
|
2174
|
+
printJson(payload);
|
|
2175
|
+
}
|
|
2176
|
+
else {
|
|
2177
|
+
console.log('');
|
|
2178
|
+
console.log(theme.warning(` ${payload.message}`));
|
|
2179
|
+
console.log('');
|
|
2180
|
+
}
|
|
2181
|
+
process.exitCode = 1;
|
|
2182
|
+
return;
|
|
2183
|
+
}
|
|
2184
|
+
});
|
|
2185
|
+
// Agent Matrix Commands
|
|
2186
|
+
const agentsCommand = program.command('agents').description('Agent Matrix - Connect and coordinate all AI agents');
|
|
2187
|
+
agentsCommand
|
|
2188
|
+
.command('register')
|
|
2189
|
+
.description('Register PHANTOM with all detected AI agents')
|
|
2190
|
+
.option('--json', 'Output as JSON')
|
|
2191
|
+
.action(async (options) => {
|
|
2192
|
+
try {
|
|
2193
|
+
if (options.json) {
|
|
2194
|
+
// JSON output for programmatic use
|
|
2195
|
+
const agents = await PhantomDiscovery.detectInstalledAgents();
|
|
2196
|
+
const installed = agents.filter((a) => a.installed);
|
|
2197
|
+
const results = [];
|
|
2198
|
+
for (const agent of installed) {
|
|
2199
|
+
const success = await PhantomDiscovery.registerWithAgent(agent.type);
|
|
2200
|
+
results.push({
|
|
2201
|
+
agent: agent.name,
|
|
2202
|
+
type: agent.type,
|
|
2203
|
+
success,
|
|
2204
|
+
status: success ? 'registered' : 'failed'
|
|
2205
|
+
});
|
|
2206
|
+
}
|
|
2207
|
+
printJson({
|
|
2208
|
+
timestamp: new Date().toISOString(),
|
|
2209
|
+
total_agents: installed.length,
|
|
2210
|
+
successful_registrations: results.filter(r => r.success).length,
|
|
2211
|
+
results
|
|
2212
|
+
});
|
|
2213
|
+
return;
|
|
2214
|
+
}
|
|
2215
|
+
// Interactive output
|
|
2216
|
+
await PhantomDiscovery.autoRegisterAll();
|
|
2217
|
+
}
|
|
2218
|
+
catch (error) {
|
|
2219
|
+
console.error(theme.error(' Failed to register agents:'), error);
|
|
2220
|
+
process.exitCode = 1;
|
|
2221
|
+
}
|
|
2222
|
+
});
|
|
2223
|
+
agentsCommand
|
|
2224
|
+
.command('health')
|
|
2225
|
+
.description('Check PHANTOM and agent connection health')
|
|
2226
|
+
.option('--json', 'Output as JSON')
|
|
2227
|
+
.action(async (options) => {
|
|
2228
|
+
try {
|
|
2229
|
+
if (options.json) {
|
|
2230
|
+
const report = await PhantomDiscovery.healthReport();
|
|
2231
|
+
printJson(report);
|
|
2232
|
+
return;
|
|
2233
|
+
}
|
|
2234
|
+
// Interactive health check
|
|
2235
|
+
await PhantomDiscovery.healthCheck();
|
|
2236
|
+
}
|
|
2237
|
+
catch (error) {
|
|
2238
|
+
console.error(theme.error(' Health check failed:'), error);
|
|
2239
|
+
process.exitCode = 1;
|
|
2240
|
+
}
|
|
2241
|
+
});
|
|
2242
|
+
agentsCommand
|
|
2243
|
+
.command('scan')
|
|
2244
|
+
.description('Scan system for installed AI agents and LLMs')
|
|
2245
|
+
.option('--register', 'Automatically register detected agents')
|
|
2246
|
+
.option('--json', 'Output as JSON')
|
|
2247
|
+
.action(async (options) => {
|
|
2248
|
+
try {
|
|
2249
|
+
let report = await PhantomDiscovery.healthReport();
|
|
2250
|
+
if (options.register) {
|
|
2251
|
+
const installed = report.agents.filter(agent => agent.installed);
|
|
2252
|
+
if (options.json) {
|
|
2253
|
+
const registrationResults = [];
|
|
2254
|
+
for (const agent of installed) {
|
|
2255
|
+
const result = await PhantomDiscovery.registerAgent(agent.type);
|
|
2256
|
+
registrationResults.push({
|
|
2257
|
+
type: agent.type,
|
|
2258
|
+
success: result.success,
|
|
2259
|
+
message: result.message,
|
|
2260
|
+
});
|
|
2261
|
+
}
|
|
2262
|
+
report = await PhantomDiscovery.healthReport();
|
|
2263
|
+
const detected = report.agents.filter(agent => agent.installed);
|
|
2264
|
+
const registered = report.agents.filter(agent => agent.registered).map(agent => agent.type);
|
|
2265
|
+
printJson({
|
|
2266
|
+
detected,
|
|
2267
|
+
registered,
|
|
2268
|
+
health: {
|
|
2269
|
+
mcp_server: report.mcp_server,
|
|
2270
|
+
totals: {
|
|
2271
|
+
detected: detected.length,
|
|
2272
|
+
registered: registered.length,
|
|
2273
|
+
},
|
|
2274
|
+
},
|
|
2275
|
+
issues: report.issues,
|
|
2276
|
+
registration: registrationResults,
|
|
2277
|
+
});
|
|
2278
|
+
return;
|
|
2279
|
+
}
|
|
2280
|
+
const summary = await PhantomDiscovery.registerAll(installed.map(agent => agent.type));
|
|
2281
|
+
report = await PhantomDiscovery.healthReport();
|
|
2282
|
+
console.log('');
|
|
2283
|
+
console.log(theme.success(` Registration complete: ${summary.success}/${summary.total} agents.`));
|
|
2284
|
+
console.log('');
|
|
2285
|
+
}
|
|
2286
|
+
const detected = report.agents.filter(agent => agent.installed);
|
|
2287
|
+
const registered = report.agents.filter(agent => agent.registered).map(agent => agent.type);
|
|
2288
|
+
if (options.json) {
|
|
2289
|
+
printJson({
|
|
2290
|
+
detected,
|
|
2291
|
+
registered,
|
|
2292
|
+
health: {
|
|
2293
|
+
mcp_server: report.mcp_server,
|
|
2294
|
+
totals: {
|
|
2295
|
+
detected: detected.length,
|
|
2296
|
+
registered: registered.length,
|
|
2297
|
+
},
|
|
2298
|
+
},
|
|
2299
|
+
issues: report.issues,
|
|
2300
|
+
});
|
|
2301
|
+
return;
|
|
2302
|
+
}
|
|
2303
|
+
console.log('');
|
|
2304
|
+
console.log(theme.title(' DETECTED AGENTS'));
|
|
2305
|
+
console.log('');
|
|
2306
|
+
if (detected.length === 0) {
|
|
2307
|
+
console.log(theme.warning(' No AI agents detected in your system.'));
|
|
2308
|
+
console.log(theme.dim(' Supported: Claude Code, Cursor, Codex CLI, VS Code, Zed, Gemini CLI'));
|
|
2309
|
+
console.log('');
|
|
2310
|
+
return;
|
|
2311
|
+
}
|
|
2312
|
+
for (const agent of detected) {
|
|
2313
|
+
const statusIcon = agent.running ? '🟢' : '🔵';
|
|
2314
|
+
const confidenceColor = agent.confidence > 80 ? theme.success :
|
|
2315
|
+
agent.confidence > 60 ? theme.warning : theme.dim;
|
|
2316
|
+
const registration = agent.registered ? theme.success('Registered') : theme.warning('Not registered');
|
|
2317
|
+
console.log(` ${statusIcon} ${theme.accent(agent.name)}`);
|
|
2318
|
+
console.log(` ${confidenceColor(`Confidence: ${agent.confidence}%`)} | Status: ${agent.status}`);
|
|
2319
|
+
console.log(` ${theme.secondary('Registration:')} ${registration}`);
|
|
2320
|
+
console.log(` ${theme.dim(agent.configPath)}`);
|
|
2321
|
+
console.log('');
|
|
2322
|
+
}
|
|
2323
|
+
if (report.issues.length > 0) {
|
|
2324
|
+
console.log(theme.warning(' Discovery issues:'));
|
|
2325
|
+
for (const issue of report.issues) {
|
|
2326
|
+
console.log(` • ${issue}`);
|
|
2327
|
+
}
|
|
2328
|
+
console.log('');
|
|
2329
|
+
}
|
|
2330
|
+
console.log(theme.dim(' Run with --register to automatically register detected agents'));
|
|
2331
|
+
console.log('');
|
|
2332
|
+
}
|
|
2333
|
+
catch (err) {
|
|
2334
|
+
const message = err instanceof Error ? err.message : 'Agent scan failed';
|
|
2335
|
+
if (options.json) {
|
|
2336
|
+
printJson({ status: 'error', error: message });
|
|
2337
|
+
}
|
|
2338
|
+
else {
|
|
2339
|
+
console.log('');
|
|
2340
|
+
console.log(theme.error(` ${message}`));
|
|
2341
|
+
console.log('');
|
|
2342
|
+
}
|
|
2343
|
+
process.exitCode = 1;
|
|
2344
|
+
}
|
|
2345
|
+
});
|
|
2346
|
+
agentsCommand
|
|
2347
|
+
.command('list')
|
|
2348
|
+
.description('List registered agents and their integration status')
|
|
2349
|
+
.option('--json', 'Output as JSON')
|
|
2350
|
+
.action(async (options) => {
|
|
2351
|
+
try {
|
|
2352
|
+
const { AgentRegistry } = await import('@phantom-pm/core');
|
|
2353
|
+
const registry = new AgentRegistry();
|
|
2354
|
+
const agents = registry.getAllAgents();
|
|
2355
|
+
if (options.json) {
|
|
2356
|
+
printJson({ agents });
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2359
|
+
console.log('');
|
|
2360
|
+
console.log(theme.title(' REGISTERED AGENTS'));
|
|
2361
|
+
console.log('');
|
|
2362
|
+
if (agents.length === 0) {
|
|
2363
|
+
console.log(theme.warning(' No agents registered yet.'));
|
|
2364
|
+
console.log(theme.dim(' Run: phantom agents scan'));
|
|
1456
2365
|
console.log('');
|
|
1457
2366
|
return;
|
|
1458
2367
|
}
|
|
@@ -1497,7 +2406,7 @@ agentsCommand
|
|
|
1497
2406
|
.option('--json', 'Output as JSON')
|
|
1498
2407
|
.action(async (agentId, options) => {
|
|
1499
2408
|
try {
|
|
1500
|
-
const { AgentRegistry } = await import('@phantom/core');
|
|
2409
|
+
const { AgentRegistry } = await import('@phantom-pm/core');
|
|
1501
2410
|
const registry = new AgentRegistry();
|
|
1502
2411
|
const validLevels = ['integrated', 'enhanced', 'full'];
|
|
1503
2412
|
if (!validLevels.includes(options.level)) {
|
|
@@ -1536,7 +2445,7 @@ agentsCommand
|
|
|
1536
2445
|
.option('--json', 'Output as JSON')
|
|
1537
2446
|
.action(async (options) => {
|
|
1538
2447
|
try {
|
|
1539
|
-
const { AgentRegistry } = await import('@phantom/core');
|
|
2448
|
+
const { AgentRegistry } = await import('@phantom-pm/core');
|
|
1540
2449
|
const registry = new AgentRegistry();
|
|
1541
2450
|
const topology = registry.getNetworkTopology();
|
|
1542
2451
|
if (options.json) {
|
|
@@ -1610,6 +2519,41 @@ program
|
|
|
1610
2519
|
.action(() => {
|
|
1611
2520
|
failNotImplemented('tools');
|
|
1612
2521
|
});
|
|
2522
|
+
// ── Chat command ──
|
|
2523
|
+
program
|
|
2524
|
+
.command('chat')
|
|
2525
|
+
.description('Interactive AI chat — connect any model and talk to Phantom')
|
|
2526
|
+
.option('--model <model>', 'Model to connect (e.g. gpt-4o, claude, gemini, ollama:llama3.1:8b)')
|
|
2527
|
+
.option('--provider <provider>', 'Force a specific provider (openai, anthropic, ollama, gemini)')
|
|
2528
|
+
.action(async (options) => {
|
|
2529
|
+
await startChat(options);
|
|
2530
|
+
});
|
|
2531
|
+
// ── Model management ──
|
|
2532
|
+
program
|
|
2533
|
+
.command('model')
|
|
2534
|
+
.description('Manage AI model connections')
|
|
2535
|
+
.argument('[action]', 'list | switch <model>', 'list')
|
|
2536
|
+
.argument('[model]', 'Model name for switch')
|
|
2537
|
+
.action(async (action, model) => {
|
|
2538
|
+
if (action === 'switch' && model) {
|
|
2539
|
+
console.log(` Use: phantom chat --model ${model}`);
|
|
2540
|
+
return;
|
|
2541
|
+
}
|
|
2542
|
+
// List available models
|
|
2543
|
+
console.log('');
|
|
2544
|
+
console.log(theme.title(' AVAILABLE MODELS'));
|
|
2545
|
+
console.log('');
|
|
2546
|
+
console.log(` ${theme.accent('Provider')} ${theme.accent('Models')}`);
|
|
2547
|
+
console.log(` ${theme.dim('─'.repeat(55))}`);
|
|
2548
|
+
console.log(` ${theme.success('ollama')} llama3.1:8b, llama3.1:70b, codellama:7b, mistral:7b`);
|
|
2549
|
+
console.log(` ${theme.success('openai')} gpt-4o, gpt-4o-mini, o3-mini`);
|
|
2550
|
+
console.log(` ${theme.success('anthropic')} claude-sonnet-4, claude-3.5-haiku, claude-3-opus`);
|
|
2551
|
+
console.log(` ${theme.success('gemini')} gemini-2.0-flash, gemini-2.5-pro, gemini-1.5-pro`);
|
|
2552
|
+
console.log('');
|
|
2553
|
+
console.log(theme.dim(' Usage: phantom chat --model <name>'));
|
|
2554
|
+
console.log(theme.dim(' Config: phantom config setup'));
|
|
2555
|
+
console.log('');
|
|
2556
|
+
});
|
|
1613
2557
|
function dirnameSafe(pathValue) {
|
|
1614
2558
|
const idx = Math.max(pathValue.lastIndexOf('/'), pathValue.lastIndexOf('\\'));
|
|
1615
2559
|
if (idx <= 0)
|
|
@@ -1623,5 +2567,34 @@ if (argv[2] === 'integrate' &&
|
|
|
1623
2567
|
!['scan', 'doctor', 'connect'].includes(argv[3])) {
|
|
1624
2568
|
argv.splice(3, 0, 'connect');
|
|
1625
2569
|
}
|
|
1626
|
-
|
|
2570
|
+
// ── Default: no command → launch interactive chat ──
|
|
2571
|
+
import React from 'react';
|
|
2572
|
+
import { render } from 'ink';
|
|
2573
|
+
import { Dashboard } from './commands/dashboard.js';
|
|
2574
|
+
// Check if command already exists to prevent duplicate registration in case of re-execution
|
|
2575
|
+
if (!program.commands.find((c) => c.name() === 'dashboard')) {
|
|
2576
|
+
const dashboardCommand = program.command('dashboard')
|
|
2577
|
+
.description('Launch localhost configuration dashboard')
|
|
2578
|
+
.option('-p, --port <number>', 'Port to run on', '3333')
|
|
2579
|
+
.action(async (options) => {
|
|
2580
|
+
const { waitUntilExit } = render(React.createElement(Dashboard, { port: parseInt(options.port) }));
|
|
2581
|
+
await waitUntilExit();
|
|
2582
|
+
});
|
|
2583
|
+
}
|
|
2584
|
+
const knownCommands = program.commands.map((c) => c.name());
|
|
2585
|
+
const userCommand = argv[2];
|
|
2586
|
+
if (!userCommand ||
|
|
2587
|
+
(userCommand && !userCommand.startsWith('-') && !knownCommands.includes(userCommand))) {
|
|
2588
|
+
// No command or unknown command → launch chat
|
|
2589
|
+
if (!userCommand) {
|
|
2590
|
+
startChat({});
|
|
2591
|
+
}
|
|
2592
|
+
else {
|
|
2593
|
+
// Treat as a question to Phantom
|
|
2594
|
+
program.parse(argv);
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
else {
|
|
2598
|
+
program.parse(argv);
|
|
2599
|
+
}
|
|
1627
2600
|
//# sourceMappingURL=index.js.map
|