@phantom-pm/cli 1.0.0 → 2.0.0-alpha.2

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/index.js CHANGED
@@ -1,10 +1,21 @@
1
1
  #!/usr/bin/env node
2
- import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
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>', 'transport mode', 'stdio')
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
- if (options.mode !== 'stdio') {
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(` Unsupported mode '${options.mode}', using stdio.`));
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
- await runStdioServer();
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 || './phantom-output/prds',
610
+ output: options.out || './.phantom/output/prds',
423
611
  });
424
- const outputPath = result.prd.filePath || './phantom-output/prds';
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-output directory')
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-output');
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-output/.'));
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>')
@@ -602,20 +799,41 @@ program
602
799
  .command('simulate <scenario>')
603
800
  .description('Run deterministic simulation for a product scenario')
604
801
  .option('--json', 'Output as JSON')
802
+ .option('--personas <n>', 'Number of personas to simulate', '3')
803
+ .option('--depth <level>', 'Simulation depth (shallow, medium, deep)', 'medium')
605
804
  .action((scenario, options) => {
606
- const result = runDeterministicSimulation(scenario);
805
+ const result = runDeterministicSimulation(scenario, {
806
+ personas: Number.parseInt(options.personas, 10),
807
+ depth: options.depth,
808
+ });
607
809
  if (options.json) {
608
810
  printJson(result);
609
811
  return;
610
812
  }
611
813
  console.log('');
612
- console.log(theme.title(' DETERMINISTIC SIMULATION'));
613
- console.log(` ${theme.secondary('Scenario:')} ${result.scenario}`);
614
- console.log(` ${theme.secondary('Seed:')} ${result.seed}`);
615
- console.log(` ${theme.secondary('Baseline:')} ${result.metrics.baseline}`);
616
- console.log(` ${theme.secondary('Projected:')} ${result.metrics.projected}`);
617
- console.log(` ${theme.secondary('Delta (%):')} ${result.metrics.deltaPercent}`);
618
- console.log(` ${theme.secondary('Confidence:')} ${result.metrics.confidence}%`);
814
+ console.log(theme.title(' === PRODUCT SIMULATION ==='));
815
+ console.log(` ${theme.secondary('Scenario:')} "${scenario}"`);
816
+ console.log('');
817
+ for (const persona of result.personas) {
818
+ console.log(` ${theme.accent(`─── PERSONA: ${persona.name} (${persona.trait}) ───`)}`);
819
+ console.log('');
820
+ for (let i = 0; i < persona.steps.length; i++) {
821
+ const step = persona.steps[i];
822
+ const icon = step.status === 'PASS' ? theme.check : step.status === 'WARN' ? theme.warning_icon : theme.error('✗');
823
+ const color = step.status === 'PASS' ? theme.success : step.status === 'WARN' ? theme.warning : theme.error;
824
+ console.log(` Step ${i + 1}: ${step.name}`);
825
+ console.log(` ${icon} ${color(`${step.status}: ${step.score}% — ${step.message}`)}`);
826
+ if (step.recommendation) {
827
+ console.log(` ${theme.dim('💡 Recommendation:')} ${theme.secondary(step.recommendation)}`);
828
+ }
829
+ console.log('');
830
+ }
831
+ }
832
+ console.log(` ${theme.accent('─── SUMMARY ───')}`);
833
+ console.log(` ${theme.secondary('Overall Funnel Completion:')} ${result.metrics.deltaPercent.toFixed(1)}%`);
834
+ console.log(` ${theme.secondary('Baseline Metrics:')} ${result.metrics.baseline}`);
835
+ console.log(` ${theme.secondary('Confidence Score:')} ${result.metrics.confidence}%`);
836
+ console.log(` ${theme.secondary('Deterministic Seed:')} ${result.seed}`);
619
837
  console.log('');
620
838
  });
621
839
  program
@@ -627,7 +845,7 @@ program
627
845
  .option('--refresh', 'Generate new nudges based on current context')
628
846
  .action(async (options) => {
629
847
  try {
630
- const { NudgeEngine, getConfig, getContextEngine, getModuleManager } = await import('@phantom/core');
848
+ const { NudgeEngine, getConfig, getContextEngine, getModuleManager } = await import('@phantom-pm/core');
631
849
  const engine = new NudgeEngine();
632
850
  // Handle dismiss/snooze actions
633
851
  if (options.dismiss) {
@@ -1178,27 +1396,32 @@ analyticsCommand
1178
1396
  console.log(` ${theme.accent('phantom analytics dashboard --categories "user-engagement,revenue"')}`);
1179
1397
  console.log('');
1180
1398
  });
1181
- docsCommand
1182
- .command('generate')
1183
- .description('Generate deterministic documentation artifacts')
1184
- .option('--out <path>', 'Output directory path')
1399
+ const oracleCommand = program.command('oracle').description('Predictive product intelligence');
1400
+ oracleCommand
1401
+ .command('predict <feature>')
1402
+ .description('Predict feature success')
1403
+ .option('--description <text>', 'Feature description')
1185
1404
  .option('--json', 'Output as JSON')
1186
- .action((options) => {
1405
+ .action(async (feature, options) => {
1187
1406
  try {
1188
- const files = generateRealDocumentation(process.cwd(), options.out);
1407
+ const result = await runModuleCommand('oracle', 'Oracle', 'oracle predict', {
1408
+ feature,
1409
+ description: options.description,
1410
+ _: ['predict', feature],
1411
+ });
1189
1412
  if (options.json) {
1190
- printJson({ files });
1413
+ printJson(result);
1191
1414
  return;
1192
1415
  }
1193
1416
  console.log('');
1194
- console.log(theme.success(' Documentation generated:'));
1195
- for (const file of files) {
1196
- console.log(` ${theme.check} ${file}`);
1197
- }
1417
+ console.log(theme.success(' Oracle prediction complete.'));
1418
+ console.log(` ${theme.secondary('Feature:')} ${feature}`);
1419
+ console.log(` ${theme.secondary('Probability:')} ${result.prediction?.successProbability ?? 'n/a'}%`);
1420
+ console.log(` ${theme.secondary('Generated:')} ${result.prediction?.generatedAt ?? 'n/a'}`);
1198
1421
  console.log('');
1199
1422
  }
1200
1423
  catch (err) {
1201
- const message = err instanceof Error ? err.message : 'Documentation generation failed';
1424
+ const message = err instanceof Error ? err.message : 'Oracle prediction failed';
1202
1425
  if (options.json) {
1203
1426
  printJson({ status: 'error', error: message });
1204
1427
  }
@@ -1210,219 +1433,140 @@ docsCommand
1210
1433
  process.exitCode = 1;
1211
1434
  }
1212
1435
  });
1213
- program
1214
- .command('frameworks [action] [framework]')
1215
- .description('List built-in PM frameworks')
1436
+ oracleCommand
1437
+ .command('simulate [scenario]')
1438
+ .description('Run Monte Carlo simulation')
1439
+ .option('--iterations <count>', 'Iteration count', '10000')
1216
1440
  .option('--json', 'Output as JSON')
1217
- .action((action, framework, options) => {
1218
- if (!action || action === 'list') {
1441
+ .action(async (scenario, options) => {
1442
+ try {
1443
+ const result = await runModuleCommand('oracle', 'Oracle', 'oracle simulate', {
1444
+ scenario: scenario || 'default',
1445
+ iterations: Number.parseInt(options.iterations || '10000', 10),
1446
+ _: ['simulate', scenario || 'default'],
1447
+ });
1219
1448
  if (options.json) {
1220
- printJson({ frameworks: FRAMEWORKS });
1449
+ printJson(result);
1221
1450
  return;
1222
1451
  }
1223
1452
  console.log('');
1224
- console.log(theme.title(' PM FRAMEWORKS'));
1225
- console.log('');
1226
- for (const fw of FRAMEWORKS) {
1227
- console.log(` ${theme.check} ${fw.name} ${theme.dim(`— ${fw.desc}`)}`);
1228
- }
1453
+ console.log(theme.success(' Simulation complete.'));
1454
+ console.log(` ${theme.secondary('Scenario:')} ${result.simulation?.scenario ?? scenario ?? 'default'}`);
1455
+ console.log(` ${theme.secondary('Confidence:')} ${result.simulation?.confidence ?? 'n/a'}%`);
1229
1456
  console.log('');
1230
- return;
1231
1457
  }
1232
- if (action === 'apply') {
1233
- const payload = {
1234
- status: 'not_implemented',
1235
- message: 'Framework auto-apply is not implemented in real runtime mode.',
1236
- framework: framework || null,
1237
- };
1458
+ catch (err) {
1459
+ const message = err instanceof Error ? err.message : 'Oracle simulation failed';
1238
1460
  if (options.json) {
1239
- printJson(payload);
1461
+ printJson({ status: 'error', error: message });
1240
1462
  }
1241
1463
  else {
1242
1464
  console.log('');
1243
- console.log(theme.warning(` ${payload.message}`));
1465
+ console.log(theme.error(` ${message}`));
1244
1466
  console.log('');
1245
1467
  }
1246
1468
  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
1469
  }
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
1470
  });
1284
- // Agent Matrix Commands
1285
- const agentsCommand = program.command('agents').description('Agent Matrix - Connect and coordinate all AI agents');
1286
- agentsCommand
1287
- .command('register')
1288
- .description('Register PHANTOM with all detected AI agents')
1471
+ oracleCommand
1472
+ .command('forecast')
1473
+ .description('Generate metric forecast')
1474
+ .option('--metric <name>', 'Metric name', 'revenue')
1475
+ .option('--period <months>', 'Period in months', '6')
1476
+ .option('--data <json>', 'Historical data JSON array')
1289
1477
  .option('--json', 'Output as JSON')
1290
1478
  .action(async (options) => {
1291
1479
  try {
1480
+ if (options.data) {
1481
+ parseJsonOption(options.data, '--data');
1482
+ }
1483
+ const result = await runModuleCommand('oracle', 'Oracle', 'oracle forecast', {
1484
+ metric: options.metric || 'revenue',
1485
+ period: Number.parseInt(options.period || '6', 10),
1486
+ data: options.data,
1487
+ _: ['forecast'],
1488
+ });
1292
1489
  if (options.json) {
1293
- // JSON output for programmatic use
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
- });
1490
+ printJson(result);
1312
1491
  return;
1313
1492
  }
1314
- // Interactive output
1315
- await PhantomDiscovery.autoRegisterAll();
1493
+ console.log('');
1494
+ console.log(theme.success(' Forecast generated.'));
1495
+ console.log(` ${theme.secondary('Metric:')} ${result.forecast?.metric ?? options.metric}`);
1496
+ console.log(` ${theme.secondary('Confidence:')} ${result.forecast?.confidence ?? 'n/a'}%`);
1497
+ console.log('');
1316
1498
  }
1317
- catch (error) {
1318
- console.error(theme.error(' Failed to register agents:'), error);
1499
+ catch (err) {
1500
+ const message = err instanceof Error ? err.message : 'Oracle forecast failed';
1501
+ if (options.json) {
1502
+ printJson({ status: 'error', error: message });
1503
+ }
1504
+ else {
1505
+ console.log('');
1506
+ console.log(theme.error(` ${message}`));
1507
+ console.log('');
1508
+ }
1319
1509
  process.exitCode = 1;
1320
1510
  }
1321
1511
  });
1322
- agentsCommand
1323
- .command('health')
1324
- .description('Check PHANTOM and agent connection health')
1512
+ oracleCommand
1513
+ .command('risk [project]')
1514
+ .description('Assess project risk')
1325
1515
  .option('--json', 'Output as JSON')
1326
- .action(async (options) => {
1516
+ .action(async (project, options) => {
1327
1517
  try {
1518
+ const result = await runModuleCommand('oracle', 'Oracle', 'oracle risk', {
1519
+ project: project || '',
1520
+ _: ['risk', project || ''],
1521
+ });
1328
1522
  if (options.json) {
1329
- // Implement JSON health check
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);
1523
+ printJson(result);
1360
1524
  return;
1361
1525
  }
1362
- // Interactive health check
1363
- await PhantomDiscovery.healthCheck();
1526
+ console.log('');
1527
+ console.log(theme.success(' Risk assessment generated.'));
1528
+ console.log(` ${theme.secondary('Overall Risk:')} ${result.risk?.overallRisk ?? 'n/a'}`);
1529
+ console.log(` ${theme.secondary('Score:')} ${result.risk?.score ?? 'n/a'}`);
1530
+ console.log('');
1364
1531
  }
1365
- catch (error) {
1366
- console.error(theme.error(' Health check failed:'), error);
1532
+ catch (err) {
1533
+ const message = err instanceof Error ? err.message : 'Oracle risk assessment failed';
1534
+ if (options.json) {
1535
+ printJson({ status: 'error', error: message });
1536
+ }
1537
+ else {
1538
+ console.log('');
1539
+ console.log(theme.error(` ${message}`));
1540
+ console.log('');
1541
+ }
1367
1542
  process.exitCode = 1;
1368
1543
  }
1369
1544
  });
1370
- agentsCommand
1371
- .command('scan')
1372
- .description('Scan system for installed AI agents and LLMs')
1373
- .option('--register', 'Automatically register detected agents')
1545
+ const experimentCommand = program.command('experiment').description('A/B test and experimentation workflow');
1546
+ experimentCommand
1547
+ .command('design <hypothesis>')
1548
+ .description('Design an experiment')
1549
+ .option('--metric <name>', 'Primary metric', 'conversion_rate')
1374
1550
  .option('--json', 'Output as JSON')
1375
- .action(async (options) => {
1551
+ .action(async (hypothesis, options) => {
1376
1552
  try {
1377
- const { AgentDiscovery, AgentRegistry } = await import('@phantom/core');
1378
- const discovery = new AgentDiscovery();
1379
- const agents = await discovery.scanSystem();
1380
- if (options.register) {
1381
- const registry = new AgentRegistry();
1382
- const registered = await registry.scanAndRegister();
1383
- if (options.json) {
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 });
1553
+ const result = await runModuleCommand('experiment-lab', 'Experiment Lab', 'experiment design', {
1554
+ hypothesis,
1555
+ metric: options.metric || 'conversion_rate',
1556
+ _: ['design', hypothesis],
1557
+ });
1558
+ if (options.json) {
1559
+ printJson(result);
1396
1560
  return;
1397
1561
  }
1398
- if (!options.register) {
1399
- console.log('');
1400
- console.log(theme.title(' DETECTED AGENTS'));
1401
- console.log('');
1402
- if (agents.length === 0) {
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
- }
1562
+ console.log('');
1563
+ console.log(theme.success(' Experiment design created.'));
1564
+ console.log(` ${theme.secondary('Experiment:')} ${result.experiment?.name ?? 'n/a'}`);
1565
+ console.log(` ${theme.secondary('Sample Size:')} ${result.experiment?.sampleSize ?? 'n/a'}`);
1566
+ console.log('');
1423
1567
  }
1424
1568
  catch (err) {
1425
- const message = err instanceof Error ? err.message : 'Agent scan failed';
1569
+ const message = err instanceof Error ? err.message : 'Experiment design failed';
1426
1570
  if (options.json) {
1427
1571
  printJson({ status: 'error', error: message });
1428
1572
  }
@@ -1434,16 +1578,802 @@ agentsCommand
1434
1578
  process.exitCode = 1;
1435
1579
  }
1436
1580
  });
1437
- agentsCommand
1438
- .command('list')
1439
- .description('List registered agents and their integration status')
1581
+ experimentCommand
1582
+ .command('analyze <experimentId>')
1583
+ .description('Analyze experiment results')
1584
+ .option('--data <json>', 'Variant data JSON object')
1440
1585
  .option('--json', 'Output as JSON')
1441
- .action(async (options) => {
1586
+ .action(async (experimentId, options) => {
1442
1587
  try {
1443
- const { AgentRegistry } = await import('@phantom/core');
1444
- const registry = new AgentRegistry();
1445
- const agents = registry.getAllAgents();
1446
- if (options.json) {
1588
+ if (options.data) {
1589
+ parseJsonOption(options.data, '--data');
1590
+ }
1591
+ const result = await runModuleCommand('experiment-lab', 'Experiment Lab', 'experiment analyze', {
1592
+ experimentId,
1593
+ data: options.data,
1594
+ _: ['analyze', experimentId],
1595
+ });
1596
+ if (options.json) {
1597
+ printJson(result);
1598
+ return;
1599
+ }
1600
+ console.log('');
1601
+ console.log(theme.success(' Experiment analysis complete.'));
1602
+ console.log(` ${theme.secondary('Winner:')} ${result.analysis?.winner ?? 'n/a'}`);
1603
+ console.log(` ${theme.secondary('Significant:')} ${result.analysis?.statisticalSignificance ?? 'n/a'}`);
1604
+ console.log('');
1605
+ }
1606
+ catch (err) {
1607
+ const message = err instanceof Error ? err.message : 'Experiment analysis failed';
1608
+ if (options.json) {
1609
+ printJson({ status: 'error', error: message });
1610
+ }
1611
+ else {
1612
+ console.log('');
1613
+ console.log(theme.error(` ${message}`));
1614
+ console.log('');
1615
+ }
1616
+ process.exitCode = 1;
1617
+ }
1618
+ });
1619
+ experimentCommand
1620
+ .command('sample-size')
1621
+ .description('Calculate required sample size')
1622
+ .option('--baseline <rate>', 'Baseline conversion rate', '0.2')
1623
+ .option('--mde <rate>', 'Minimum detectable effect', '0.05')
1624
+ .option('--confidence <rate>', 'Confidence level', '0.95')
1625
+ .option('--power <rate>', 'Statistical power', '0.8')
1626
+ .option('--json', 'Output as JSON')
1627
+ .action(async (options) => {
1628
+ try {
1629
+ const result = await runModuleCommand('experiment-lab', 'Experiment Lab', 'experiment sample-size', {
1630
+ baseline: Number.parseFloat(options.baseline || '0.2'),
1631
+ mde: Number.parseFloat(options.mde || '0.05'),
1632
+ confidence: Number.parseFloat(options.confidence || '0.95'),
1633
+ power: Number.parseFloat(options.power || '0.8'),
1634
+ _: ['sample-size'],
1635
+ });
1636
+ if (options.json) {
1637
+ printJson(result);
1638
+ return;
1639
+ }
1640
+ console.log('');
1641
+ console.log(theme.success(' Sample size calculation complete.'));
1642
+ console.log(` ${theme.secondary('Sample Size:')} ${result.calculation?.sampleSize ?? 'n/a'}`);
1643
+ console.log(` ${theme.secondary('Duration (days):')} ${result.calculation?.duration ?? 'n/a'}`);
1644
+ console.log('');
1645
+ }
1646
+ catch (err) {
1647
+ const message = err instanceof Error ? err.message : 'Sample size calculation failed';
1648
+ if (options.json) {
1649
+ printJson({ status: 'error', error: message });
1650
+ }
1651
+ else {
1652
+ console.log('');
1653
+ console.log(theme.error(` ${message}`));
1654
+ console.log('');
1655
+ }
1656
+ process.exitCode = 1;
1657
+ }
1658
+ });
1659
+ experimentCommand
1660
+ .command('rollout <experimentId>')
1661
+ .description('Create rollout strategy')
1662
+ .option('--phases <count>', 'Rollout phases', '3')
1663
+ .option('--json', 'Output as JSON')
1664
+ .action(async (experimentId, options) => {
1665
+ try {
1666
+ const result = await runModuleCommand('experiment-lab', 'Experiment Lab', 'experiment rollout', {
1667
+ experimentId,
1668
+ phases: Number.parseInt(options.phases || '3', 10),
1669
+ _: ['rollout', experimentId],
1670
+ });
1671
+ if (options.json) {
1672
+ printJson(result);
1673
+ return;
1674
+ }
1675
+ console.log('');
1676
+ console.log(theme.success(' Rollout strategy created.'));
1677
+ console.log(` ${theme.secondary('Phases:')} ${result.strategy?.phases?.length ?? 'n/a'}`);
1678
+ console.log(` ${theme.secondary('Risk Level:')} ${result.strategy?.riskLevel ?? 'n/a'}`);
1679
+ console.log('');
1680
+ }
1681
+ catch (err) {
1682
+ const message = err instanceof Error ? err.message : 'Rollout strategy failed';
1683
+ if (options.json) {
1684
+ printJson({ status: 'error', error: message });
1685
+ }
1686
+ else {
1687
+ console.log('');
1688
+ console.log(theme.error(` ${message}`));
1689
+ console.log('');
1690
+ }
1691
+ process.exitCode = 1;
1692
+ }
1693
+ });
1694
+ const uxCommand = program.command('ux').description('UX auditing and WCAG checks');
1695
+ uxCommand
1696
+ .command('audit <imagePath>')
1697
+ .description('Audit a UI screenshot')
1698
+ .option('--page-type <type>', 'Page type', 'generic')
1699
+ .option('--no-wcag', 'Skip WCAG checks')
1700
+ .option('--json', 'Output as JSON')
1701
+ .action(async (imagePath, options) => {
1702
+ try {
1703
+ const result = await runModuleCommand('ux-auditor', 'UX Auditor', 'ux audit', {
1704
+ imagePath,
1705
+ pageType: options.pageType || 'generic',
1706
+ wcag: options.wcag !== false,
1707
+ _: ['audit', imagePath],
1708
+ });
1709
+ if (options.json) {
1710
+ printJson(result);
1711
+ return;
1712
+ }
1713
+ console.log('');
1714
+ console.log(theme.success(' UX audit complete.'));
1715
+ console.log(` ${theme.secondary('Score:')} ${result.audit?.overallScore ?? 'n/a'}`);
1716
+ console.log(` ${theme.secondary('Issues:')} ${result.audit?.issues?.length ?? 'n/a'}`);
1717
+ console.log('');
1718
+ }
1719
+ catch (err) {
1720
+ const message = err instanceof Error ? err.message : 'UX audit failed';
1721
+ if (options.json) {
1722
+ printJson({ status: 'error', error: message });
1723
+ }
1724
+ else {
1725
+ console.log('');
1726
+ console.log(theme.error(` ${message}`));
1727
+ console.log('');
1728
+ }
1729
+ process.exitCode = 1;
1730
+ }
1731
+ });
1732
+ uxCommand
1733
+ .command('score <imagePath>')
1734
+ .description('Get quick UX score')
1735
+ .option('--json', 'Output as JSON')
1736
+ .action(async (imagePath, options) => {
1737
+ try {
1738
+ const result = await runModuleCommand('ux-auditor', 'UX Auditor', 'ux score', {
1739
+ imagePath,
1740
+ _: ['score', imagePath],
1741
+ });
1742
+ if (options.json) {
1743
+ printJson(result);
1744
+ return;
1745
+ }
1746
+ console.log('');
1747
+ console.log(theme.success(' UX score generated.'));
1748
+ console.log(` ${theme.secondary('Overall:')} ${result.scores?.overall ?? 'n/a'}`);
1749
+ console.log('');
1750
+ }
1751
+ catch (err) {
1752
+ const message = err instanceof Error ? err.message : 'UX score failed';
1753
+ if (options.json) {
1754
+ printJson({ status: 'error', error: message });
1755
+ }
1756
+ else {
1757
+ console.log('');
1758
+ console.log(theme.error(` ${message}`));
1759
+ console.log('');
1760
+ }
1761
+ process.exitCode = 1;
1762
+ }
1763
+ });
1764
+ uxCommand
1765
+ .command('compare <before> <after>')
1766
+ .description('Compare UX between two screenshots')
1767
+ .option('--json', 'Output as JSON')
1768
+ .action(async (before, after, options) => {
1769
+ try {
1770
+ const result = await runModuleCommand('ux-auditor', 'UX Auditor', 'ux compare', {
1771
+ before,
1772
+ after,
1773
+ _: ['compare', before, after],
1774
+ });
1775
+ if (options.json) {
1776
+ printJson(result);
1777
+ return;
1778
+ }
1779
+ console.log('');
1780
+ console.log(theme.success(' UX comparison complete.'));
1781
+ console.log(` ${theme.secondary('Delta:')} ${result.comparison?.scoreDifference ?? 'n/a'}`);
1782
+ console.log('');
1783
+ }
1784
+ catch (err) {
1785
+ const message = err instanceof Error ? err.message : 'UX comparison failed';
1786
+ if (options.json) {
1787
+ printJson({ status: 'error', error: message });
1788
+ }
1789
+ else {
1790
+ console.log('');
1791
+ console.log(theme.error(` ${message}`));
1792
+ console.log('');
1793
+ }
1794
+ process.exitCode = 1;
1795
+ }
1796
+ });
1797
+ uxCommand
1798
+ .command('wcag <imagePath>')
1799
+ .description('Generate WCAG compliance report')
1800
+ .option('--level <level>', 'WCAG level (A|AA|AAA)', 'AA')
1801
+ .option('--json', 'Output as JSON')
1802
+ .action(async (imagePath, options) => {
1803
+ try {
1804
+ const result = await runModuleCommand('ux-auditor', 'UX Auditor', 'ux wcag', {
1805
+ imagePath,
1806
+ level: options.level || 'AA',
1807
+ _: ['wcag', imagePath],
1808
+ });
1809
+ if (options.json) {
1810
+ printJson(result);
1811
+ return;
1812
+ }
1813
+ console.log('');
1814
+ console.log(theme.success(' WCAG report generated.'));
1815
+ console.log(` ${theme.secondary('Level:')} ${result.wcag?.level ?? options.level}`);
1816
+ console.log(` ${theme.secondary('Score:')} ${result.wcag?.score ?? 'n/a'}`);
1817
+ console.log('');
1818
+ }
1819
+ catch (err) {
1820
+ const message = err instanceof Error ? err.message : 'WCAG report failed';
1821
+ if (options.json) {
1822
+ printJson({ status: 'error', error: message });
1823
+ }
1824
+ else {
1825
+ console.log('');
1826
+ console.log(theme.error(` ${message}`));
1827
+ console.log('');
1828
+ }
1829
+ process.exitCode = 1;
1830
+ }
1831
+ });
1832
+ const timeMachineCommand = program.command('timemachine').description('Decision snapshots and what-if analysis');
1833
+ timeMachineCommand
1834
+ .command('snapshot')
1835
+ .description('Create a product snapshot')
1836
+ .option('--name <name>', 'Snapshot name')
1837
+ .option('--description <text>', 'Snapshot description')
1838
+ .option('--tags <csv>', 'Comma-separated tags')
1839
+ .option('--json', 'Output as JSON')
1840
+ .action(async (options) => {
1841
+ try {
1842
+ const result = await runModuleCommand('time-machine', 'Time Machine', 'timemachine snapshot', {
1843
+ name: options.name,
1844
+ description: options.description,
1845
+ tags: options.tags,
1846
+ _: ['snapshot'],
1847
+ });
1848
+ if (options.json) {
1849
+ printJson(result);
1850
+ return;
1851
+ }
1852
+ console.log('');
1853
+ console.log(theme.success(' Snapshot created.'));
1854
+ console.log(` ${theme.secondary('Snapshot ID:')} ${result.snapshot?.id ?? 'n/a'}`);
1855
+ console.log(` ${theme.secondary('Name:')} ${result.snapshot?.name ?? 'n/a'}`);
1856
+ console.log('');
1857
+ }
1858
+ catch (err) {
1859
+ const message = err instanceof Error ? err.message : 'Snapshot creation failed';
1860
+ if (options.json) {
1861
+ printJson({ status: 'error', error: message });
1862
+ }
1863
+ else {
1864
+ console.log('');
1865
+ console.log(theme.error(` ${message}`));
1866
+ console.log('');
1867
+ }
1868
+ process.exitCode = 1;
1869
+ }
1870
+ });
1871
+ timeMachineCommand
1872
+ .command('compare <id1> <id2>')
1873
+ .description('Compare two snapshots')
1874
+ .option('--json', 'Output as JSON')
1875
+ .action(async (id1, id2, options) => {
1876
+ try {
1877
+ const result = await runModuleCommand('time-machine', 'Time Machine', 'timemachine compare', {
1878
+ id1,
1879
+ id2,
1880
+ _: ['compare', id1, id2],
1881
+ });
1882
+ if (options.json) {
1883
+ printJson(result);
1884
+ return;
1885
+ }
1886
+ console.log('');
1887
+ console.log(theme.success(' Snapshot comparison complete.'));
1888
+ console.log(` ${theme.secondary('Added Decisions:')} ${result.comparison?.addedDecisions?.length ?? 'n/a'}`);
1889
+ console.log(` ${theme.secondary('Changed Decisions:')} ${result.comparison?.changedDecisions?.length ?? 'n/a'}`);
1890
+ console.log('');
1891
+ }
1892
+ catch (err) {
1893
+ const message = err instanceof Error ? err.message : 'Snapshot comparison failed';
1894
+ if (options.json) {
1895
+ printJson({ status: 'error', error: message });
1896
+ }
1897
+ else {
1898
+ console.log('');
1899
+ console.log(theme.error(` ${message}`));
1900
+ console.log('');
1901
+ }
1902
+ process.exitCode = 1;
1903
+ }
1904
+ });
1905
+ timeMachineCommand
1906
+ .command('list')
1907
+ .description('List saved snapshots')
1908
+ .option('--json', 'Output as JSON')
1909
+ .action(async (options) => {
1910
+ try {
1911
+ const result = await runModuleCommand('time-machine', 'Time Machine', 'timemachine list', {
1912
+ _: ['list'],
1913
+ });
1914
+ if (options.json) {
1915
+ printJson(result);
1916
+ return;
1917
+ }
1918
+ console.log('');
1919
+ console.log(theme.success(' Snapshots loaded.'));
1920
+ console.log(` ${theme.secondary('Count:')} ${result.count ?? 0}`);
1921
+ console.log('');
1922
+ }
1923
+ catch (err) {
1924
+ const message = err instanceof Error ? err.message : 'Snapshot list failed';
1925
+ if (options.json) {
1926
+ printJson({ status: 'error', error: message });
1927
+ }
1928
+ else {
1929
+ console.log('');
1930
+ console.log(theme.error(` ${message}`));
1931
+ console.log('');
1932
+ }
1933
+ process.exitCode = 1;
1934
+ }
1935
+ });
1936
+ timeMachineCommand
1937
+ .command('whatif <baseId>')
1938
+ .description('Create a what-if scenario')
1939
+ .option('--name <name>', 'Scenario name')
1940
+ .option('--decision <json>', 'Decision JSON payload')
1941
+ .option('--json', 'Output as JSON')
1942
+ .action(async (baseId, options) => {
1943
+ try {
1944
+ const decision = parseJsonOption(options.decision, '--decision');
1945
+ const result = await runModuleCommand('time-machine', 'Time Machine', 'timemachine whatif', {
1946
+ baseId,
1947
+ name: options.name,
1948
+ decision,
1949
+ _: ['whatif', baseId],
1950
+ });
1951
+ if (options.json) {
1952
+ printJson(result);
1953
+ return;
1954
+ }
1955
+ console.log('');
1956
+ console.log(theme.success(' What-if scenario created.'));
1957
+ console.log(` ${theme.secondary('Scenario ID:')} ${result.scenario?.id ?? 'n/a'}`);
1958
+ console.log(` ${theme.secondary('Risk:')} ${result.scenario?.riskAssessment?.overallRisk ?? 'n/a'}`);
1959
+ console.log('');
1960
+ }
1961
+ catch (err) {
1962
+ const message = err instanceof Error ? err.message : 'What-if scenario failed';
1963
+ if (options.json) {
1964
+ printJson({ status: 'error', error: message });
1965
+ }
1966
+ else {
1967
+ console.log('');
1968
+ console.log(theme.error(` ${message}`));
1969
+ console.log('');
1970
+ }
1971
+ process.exitCode = 1;
1972
+ }
1973
+ });
1974
+ const figmaCommand = program.command('figma').description('Figma integration and design analysis');
1975
+ figmaCommand
1976
+ .command('sync <fileKey>')
1977
+ .description('Sync a Figma file')
1978
+ .option('--json', 'Output as JSON')
1979
+ .action(async (fileKey, options) => {
1980
+ try {
1981
+ const result = await runModuleCommand('figma-bridge', 'Figma Bridge', 'figma sync', {
1982
+ fileKey,
1983
+ _: ['sync', fileKey],
1984
+ });
1985
+ if (options.json) {
1986
+ printJson(result);
1987
+ return;
1988
+ }
1989
+ console.log('');
1990
+ console.log(theme.success(' Figma sync complete.'));
1991
+ console.log(` ${theme.secondary('Pages Synced:')} ${result.sync?.pagesSynced ?? 'n/a'}`);
1992
+ console.log('');
1993
+ }
1994
+ catch (err) {
1995
+ const message = err instanceof Error ? err.message : 'Figma sync failed';
1996
+ if (options.json) {
1997
+ printJson({ status: 'error', error: message });
1998
+ }
1999
+ else {
2000
+ console.log('');
2001
+ console.log(theme.error(` ${message}`));
2002
+ console.log('');
2003
+ }
2004
+ process.exitCode = 1;
2005
+ }
2006
+ });
2007
+ figmaCommand
2008
+ .command('analyze <fileKey>')
2009
+ .description('Analyze a Figma design')
2010
+ .option('--json', 'Output as JSON')
2011
+ .action(async (fileKey, options) => {
2012
+ try {
2013
+ const result = await runModuleCommand('figma-bridge', 'Figma Bridge', 'figma analyze', {
2014
+ fileKey,
2015
+ _: ['analyze', fileKey],
2016
+ });
2017
+ if (options.json) {
2018
+ printJson(result);
2019
+ return;
2020
+ }
2021
+ console.log('');
2022
+ console.log(theme.success(' Figma design analysis complete.'));
2023
+ console.log(` ${theme.secondary('Screens:')} ${result.analysis?.screens?.length ?? 'n/a'}`);
2024
+ console.log(` ${theme.secondary('Components:')} ${result.analysis?.components?.length ?? 'n/a'}`);
2025
+ console.log('');
2026
+ }
2027
+ catch (err) {
2028
+ const message = err instanceof Error ? err.message : 'Figma analysis failed';
2029
+ if (options.json) {
2030
+ printJson({ status: 'error', error: message });
2031
+ }
2032
+ else {
2033
+ console.log('');
2034
+ console.log(theme.error(` ${message}`));
2035
+ console.log('');
2036
+ }
2037
+ process.exitCode = 1;
2038
+ }
2039
+ });
2040
+ figmaCommand
2041
+ .command('stories <fileKey>')
2042
+ .description('Generate stories from Figma design')
2043
+ .option('--json', 'Output as JSON')
2044
+ .action(async (fileKey, options) => {
2045
+ try {
2046
+ const result = await runModuleCommand('figma-bridge', 'Figma Bridge', 'figma stories', {
2047
+ fileKey,
2048
+ _: ['stories', fileKey],
2049
+ });
2050
+ if (options.json) {
2051
+ printJson(result);
2052
+ return;
2053
+ }
2054
+ console.log('');
2055
+ console.log(theme.success(' Stories generated from Figma.'));
2056
+ console.log(` ${theme.secondary('Count:')} ${result.count ?? 0}`);
2057
+ console.log('');
2058
+ }
2059
+ catch (err) {
2060
+ const message = err instanceof Error ? err.message : 'Figma story generation failed';
2061
+ if (options.json) {
2062
+ printJson({ status: 'error', error: message });
2063
+ }
2064
+ else {
2065
+ console.log('');
2066
+ console.log(theme.error(` ${message}`));
2067
+ console.log('');
2068
+ }
2069
+ process.exitCode = 1;
2070
+ }
2071
+ });
2072
+ figmaCommand
2073
+ .command('prd <fileKey>')
2074
+ .description('Generate PRD from Figma design')
2075
+ .option('--title <name>', 'PRD title')
2076
+ .option('--json', 'Output as JSON')
2077
+ .action(async (fileKey, options) => {
2078
+ try {
2079
+ const result = await runModuleCommand('figma-bridge', 'Figma Bridge', 'figma prd', {
2080
+ fileKey,
2081
+ title: options.title,
2082
+ _: ['prd', fileKey],
2083
+ });
2084
+ if (options.json) {
2085
+ printJson(result);
2086
+ return;
2087
+ }
2088
+ console.log('');
2089
+ console.log(theme.success(' PRD generated from Figma.'));
2090
+ console.log(` ${theme.secondary('PRD ID:')} ${result.prd?.id ?? 'n/a'}`);
2091
+ console.log('');
2092
+ }
2093
+ catch (err) {
2094
+ const message = err instanceof Error ? err.message : 'Figma PRD generation failed';
2095
+ if (options.json) {
2096
+ printJson({ status: 'error', error: message });
2097
+ }
2098
+ else {
2099
+ console.log('');
2100
+ console.log(theme.error(` ${message}`));
2101
+ console.log('');
2102
+ }
2103
+ process.exitCode = 1;
2104
+ }
2105
+ });
2106
+ figmaCommand
2107
+ .command('list')
2108
+ .description('List cached Figma files')
2109
+ .option('--json', 'Output as JSON')
2110
+ .action(async (options) => {
2111
+ try {
2112
+ const result = await runModuleCommand('figma-bridge', 'Figma Bridge', 'figma list', {
2113
+ _: ['list'],
2114
+ });
2115
+ if (options.json) {
2116
+ printJson(result);
2117
+ return;
2118
+ }
2119
+ console.log('');
2120
+ console.log(theme.success(' Cached Figma files loaded.'));
2121
+ console.log(` ${theme.secondary('Count:')} ${result.count ?? 0}`);
2122
+ console.log('');
2123
+ }
2124
+ catch (err) {
2125
+ const message = err instanceof Error ? err.message : 'Figma file list failed';
2126
+ if (options.json) {
2127
+ printJson({ status: 'error', error: message });
2128
+ }
2129
+ else {
2130
+ console.log('');
2131
+ console.log(theme.error(` ${message}`));
2132
+ console.log('');
2133
+ }
2134
+ process.exitCode = 1;
2135
+ }
2136
+ });
2137
+ docsCommand
2138
+ .command('generate')
2139
+ .description('Generate deterministic documentation artifacts')
2140
+ .option('--out <path>', 'Output directory path')
2141
+ .option('--json', 'Output as JSON')
2142
+ .action((options) => {
2143
+ try {
2144
+ const files = generateRealDocumentation(process.cwd(), options.out);
2145
+ if (options.json) {
2146
+ printJson({ files });
2147
+ return;
2148
+ }
2149
+ console.log('');
2150
+ console.log(theme.success(' Documentation generated:'));
2151
+ for (const file of files) {
2152
+ console.log(` ${theme.check} ${file}`);
2153
+ }
2154
+ console.log('');
2155
+ }
2156
+ catch (err) {
2157
+ const message = err instanceof Error ? err.message : 'Documentation generation failed';
2158
+ if (options.json) {
2159
+ printJson({ status: 'error', error: message });
2160
+ }
2161
+ else {
2162
+ console.log('');
2163
+ console.log(theme.error(` ${message}`));
2164
+ console.log('');
2165
+ }
2166
+ process.exitCode = 1;
2167
+ }
2168
+ });
2169
+ program
2170
+ .command('frameworks [action] [framework]')
2171
+ .description('List built-in PM frameworks')
2172
+ .option('--json', 'Output as JSON')
2173
+ .action((action, framework, options) => {
2174
+ if (!action || action === 'list') {
2175
+ if (options.json) {
2176
+ printJson({ frameworks: FRAMEWORKS });
2177
+ return;
2178
+ }
2179
+ console.log('');
2180
+ console.log(theme.title(' PM FRAMEWORKS'));
2181
+ console.log('');
2182
+ for (const fw of FRAMEWORKS) {
2183
+ console.log(` ${theme.check} ${fw.name} ${theme.dim(`— ${fw.desc}`)}`);
2184
+ }
2185
+ console.log('');
2186
+ return;
2187
+ }
2188
+ if (action === 'apply') {
2189
+ const payload = {
2190
+ status: 'not_implemented',
2191
+ message: 'Framework auto-apply is not implemented in real runtime mode.',
2192
+ framework: framework || null,
2193
+ };
2194
+ if (options.json) {
2195
+ printJson(payload);
2196
+ }
2197
+ else {
2198
+ console.log('');
2199
+ console.log(theme.warning(` ${payload.message}`));
2200
+ console.log('');
2201
+ }
2202
+ process.exitCode = 1;
2203
+ return;
2204
+ }
2205
+ });
2206
+ // Agent Matrix Commands
2207
+ const agentsCommand = program.command('agents').description('Agent Matrix - Connect and coordinate all AI agents');
2208
+ agentsCommand
2209
+ .command('register')
2210
+ .description('Register PHANTOM with all detected AI agents')
2211
+ .option('--json', 'Output as JSON')
2212
+ .action(async (options) => {
2213
+ try {
2214
+ if (options.json) {
2215
+ // JSON output for programmatic use
2216
+ const agents = await PhantomDiscovery.detectInstalledAgents();
2217
+ const installed = agents.filter((a) => a.installed);
2218
+ const results = [];
2219
+ for (const agent of installed) {
2220
+ const success = await PhantomDiscovery.registerWithAgent(agent.type);
2221
+ results.push({
2222
+ agent: agent.name,
2223
+ type: agent.type,
2224
+ success,
2225
+ status: success ? 'registered' : 'failed'
2226
+ });
2227
+ }
2228
+ printJson({
2229
+ timestamp: new Date().toISOString(),
2230
+ total_agents: installed.length,
2231
+ successful_registrations: results.filter(r => r.success).length,
2232
+ results
2233
+ });
2234
+ return;
2235
+ }
2236
+ // Interactive output
2237
+ await PhantomDiscovery.autoRegisterAll();
2238
+ }
2239
+ catch (error) {
2240
+ console.error(theme.error(' Failed to register agents:'), error);
2241
+ process.exitCode = 1;
2242
+ }
2243
+ });
2244
+ agentsCommand
2245
+ .command('health')
2246
+ .description('Check PHANTOM and agent connection health')
2247
+ .option('--json', 'Output as JSON')
2248
+ .action(async (options) => {
2249
+ try {
2250
+ if (options.json) {
2251
+ const report = await PhantomDiscovery.healthReport();
2252
+ printJson(report);
2253
+ return;
2254
+ }
2255
+ // Interactive health check
2256
+ await PhantomDiscovery.healthCheck();
2257
+ }
2258
+ catch (error) {
2259
+ console.error(theme.error(' Health check failed:'), error);
2260
+ process.exitCode = 1;
2261
+ }
2262
+ });
2263
+ agentsCommand
2264
+ .command('scan')
2265
+ .description('Scan system for installed AI agents and LLMs')
2266
+ .option('--register', 'Automatically register detected agents')
2267
+ .option('--json', 'Output as JSON')
2268
+ .action(async (options) => {
2269
+ try {
2270
+ let report = await PhantomDiscovery.healthReport();
2271
+ if (options.register) {
2272
+ const installed = report.agents.filter(agent => agent.installed);
2273
+ if (options.json) {
2274
+ const registrationResults = [];
2275
+ for (const agent of installed) {
2276
+ const result = await PhantomDiscovery.registerAgent(agent.type);
2277
+ registrationResults.push({
2278
+ type: agent.type,
2279
+ success: result.success,
2280
+ message: result.message,
2281
+ });
2282
+ }
2283
+ report = await PhantomDiscovery.healthReport();
2284
+ const detected = report.agents.filter(agent => agent.installed);
2285
+ const registered = report.agents.filter(agent => agent.registered).map(agent => agent.type);
2286
+ printJson({
2287
+ detected,
2288
+ registered,
2289
+ health: {
2290
+ mcp_server: report.mcp_server,
2291
+ totals: {
2292
+ detected: detected.length,
2293
+ registered: registered.length,
2294
+ },
2295
+ },
2296
+ issues: report.issues,
2297
+ registration: registrationResults,
2298
+ });
2299
+ return;
2300
+ }
2301
+ const summary = await PhantomDiscovery.registerAll(installed.map(agent => agent.type));
2302
+ report = await PhantomDiscovery.healthReport();
2303
+ console.log('');
2304
+ console.log(theme.success(` Registration complete: ${summary.success}/${summary.total} agents.`));
2305
+ console.log('');
2306
+ }
2307
+ const detected = report.agents.filter(agent => agent.installed);
2308
+ const registered = report.agents.filter(agent => agent.registered).map(agent => agent.type);
2309
+ if (options.json) {
2310
+ printJson({
2311
+ detected,
2312
+ registered,
2313
+ health: {
2314
+ mcp_server: report.mcp_server,
2315
+ totals: {
2316
+ detected: detected.length,
2317
+ registered: registered.length,
2318
+ },
2319
+ },
2320
+ issues: report.issues,
2321
+ });
2322
+ return;
2323
+ }
2324
+ console.log('');
2325
+ console.log(theme.title(' DETECTED AGENTS'));
2326
+ console.log('');
2327
+ if (detected.length === 0) {
2328
+ console.log(theme.warning(' No AI agents detected in your system.'));
2329
+ console.log(theme.dim(' Supported: Claude Code, Cursor, Codex CLI, VS Code, Zed, Gemini CLI'));
2330
+ console.log('');
2331
+ return;
2332
+ }
2333
+ for (const agent of detected) {
2334
+ const statusIcon = agent.running ? '🟢' : '🔵';
2335
+ const confidenceColor = agent.confidence > 80 ? theme.success :
2336
+ agent.confidence > 60 ? theme.warning : theme.dim;
2337
+ const registration = agent.registered ? theme.success('Registered') : theme.warning('Not registered');
2338
+ console.log(` ${statusIcon} ${theme.accent(agent.name)}`);
2339
+ console.log(` ${confidenceColor(`Confidence: ${agent.confidence}%`)} | Status: ${agent.status}`);
2340
+ console.log(` ${theme.secondary('Registration:')} ${registration}`);
2341
+ console.log(` ${theme.dim(agent.configPath)}`);
2342
+ console.log('');
2343
+ }
2344
+ if (report.issues.length > 0) {
2345
+ console.log(theme.warning(' Discovery issues:'));
2346
+ for (const issue of report.issues) {
2347
+ console.log(` • ${issue}`);
2348
+ }
2349
+ console.log('');
2350
+ }
2351
+ console.log(theme.dim(' Run with --register to automatically register detected agents'));
2352
+ console.log('');
2353
+ }
2354
+ catch (err) {
2355
+ const message = err instanceof Error ? err.message : 'Agent scan failed';
2356
+ if (options.json) {
2357
+ printJson({ status: 'error', error: message });
2358
+ }
2359
+ else {
2360
+ console.log('');
2361
+ console.log(theme.error(` ${message}`));
2362
+ console.log('');
2363
+ }
2364
+ process.exitCode = 1;
2365
+ }
2366
+ });
2367
+ agentsCommand
2368
+ .command('list')
2369
+ .description('List registered agents and their integration status')
2370
+ .option('--json', 'Output as JSON')
2371
+ .action(async (options) => {
2372
+ try {
2373
+ const { AgentRegistry } = await import('@phantom-pm/core');
2374
+ const registry = new AgentRegistry();
2375
+ const agents = registry.getAllAgents();
2376
+ if (options.json) {
1447
2377
  printJson({ agents });
1448
2378
  return;
1449
2379
  }
@@ -1497,7 +2427,7 @@ agentsCommand
1497
2427
  .option('--json', 'Output as JSON')
1498
2428
  .action(async (agentId, options) => {
1499
2429
  try {
1500
- const { AgentRegistry } = await import('@phantom/core');
2430
+ const { AgentRegistry } = await import('@phantom-pm/core');
1501
2431
  const registry = new AgentRegistry();
1502
2432
  const validLevels = ['integrated', 'enhanced', 'full'];
1503
2433
  if (!validLevels.includes(options.level)) {
@@ -1536,7 +2466,7 @@ agentsCommand
1536
2466
  .option('--json', 'Output as JSON')
1537
2467
  .action(async (options) => {
1538
2468
  try {
1539
- const { AgentRegistry } = await import('@phantom/core');
2469
+ const { AgentRegistry } = await import('@phantom-pm/core');
1540
2470
  const registry = new AgentRegistry();
1541
2471
  const topology = registry.getNetworkTopology();
1542
2472
  if (options.json) {
@@ -1610,6 +2540,41 @@ program
1610
2540
  .action(() => {
1611
2541
  failNotImplemented('tools');
1612
2542
  });
2543
+ // ── Chat command ──
2544
+ program
2545
+ .command('chat')
2546
+ .description('Interactive AI chat — connect any model and talk to Phantom')
2547
+ .option('--model <model>', 'Model to connect (e.g. gpt-4o, claude, gemini, ollama:llama3.1:8b)')
2548
+ .option('--provider <provider>', 'Force a specific provider (openai, anthropic, ollama, gemini)')
2549
+ .action(async (options) => {
2550
+ await startChat(options);
2551
+ });
2552
+ // ── Model management ──
2553
+ program
2554
+ .command('model')
2555
+ .description('Manage AI model connections')
2556
+ .argument('[action]', 'list | switch <model>', 'list')
2557
+ .argument('[model]', 'Model name for switch')
2558
+ .action(async (action, model) => {
2559
+ if (action === 'switch' && model) {
2560
+ console.log(` Use: phantom chat --model ${model}`);
2561
+ return;
2562
+ }
2563
+ // List available models
2564
+ console.log('');
2565
+ console.log(theme.title(' AVAILABLE MODELS'));
2566
+ console.log('');
2567
+ console.log(` ${theme.accent('Provider')} ${theme.accent('Models')}`);
2568
+ console.log(` ${theme.dim('─'.repeat(55))}`);
2569
+ console.log(` ${theme.success('ollama')} llama3.1:8b, llama3.1:70b, codellama:7b, mistral:7b`);
2570
+ console.log(` ${theme.success('openai')} gpt-4o, gpt-4o-mini, o3-mini`);
2571
+ console.log(` ${theme.success('anthropic')} claude-sonnet-4, claude-3.5-haiku, claude-3-opus`);
2572
+ console.log(` ${theme.success('gemini')} gemini-3.1-pro, gemini-3.1-pro, gemini-3.1-pro`);
2573
+ console.log('');
2574
+ console.log(theme.dim(' Usage: phantom chat --model <name>'));
2575
+ console.log(theme.dim(' Config: phantom config setup'));
2576
+ console.log('');
2577
+ });
1613
2578
  function dirnameSafe(pathValue) {
1614
2579
  const idx = Math.max(pathValue.lastIndexOf('/'), pathValue.lastIndexOf('\\'));
1615
2580
  if (idx <= 0)
@@ -1623,5 +2588,34 @@ if (argv[2] === 'integrate' &&
1623
2588
  !['scan', 'doctor', 'connect'].includes(argv[3])) {
1624
2589
  argv.splice(3, 0, 'connect');
1625
2590
  }
1626
- program.parse(argv);
2591
+ // ── Default: no command → launch interactive chat ──
2592
+ import React from 'react';
2593
+ import { render } from 'ink';
2594
+ import { Dashboard } from './commands/dashboard.js';
2595
+ // Check if command already exists to prevent duplicate registration in case of re-execution
2596
+ if (!program.commands.find((c) => c.name() === 'dashboard')) {
2597
+ const dashboardCommand = program.command('dashboard')
2598
+ .description('Launch localhost configuration dashboard')
2599
+ .option('-p, --port <number>', 'Port to run on', '3333')
2600
+ .action(async (options) => {
2601
+ const { waitUntilExit } = render(React.createElement(Dashboard, { port: parseInt(options.port) }));
2602
+ await waitUntilExit();
2603
+ });
2604
+ }
2605
+ const knownCommands = program.commands.map((c) => c.name());
2606
+ const userCommand = argv[2];
2607
+ if (!userCommand ||
2608
+ (userCommand && !userCommand.startsWith('-') && !knownCommands.includes(userCommand))) {
2609
+ // No command or unknown command → launch chat
2610
+ if (!userCommand) {
2611
+ startChat({});
2612
+ }
2613
+ else {
2614
+ // Treat as a question to Phantom
2615
+ program.parse(argv);
2616
+ }
2617
+ }
2618
+ else {
2619
+ program.parse(argv);
2620
+ }
1627
2621
  //# sourceMappingURL=index.js.map