@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/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>')
@@ -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
- docsCommand
1182
- .command('generate')
1183
- .description('Generate deterministic documentation artifacts')
1184
- .option('--out <path>', 'Output directory path')
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 files = generateRealDocumentation(process.cwd(), options.out);
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({ files });
1392
+ printJson(result);
1191
1393
  return;
1192
1394
  }
1193
1395
  console.log('');
1194
- console.log(theme.success(' Documentation generated:'));
1195
- for (const file of files) {
1196
- console.log(` ${theme.check} ${file}`);
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 : 'Documentation generation failed';
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
- program
1214
- .command('frameworks [action] [framework]')
1215
- .description('List built-in PM frameworks')
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((action, framework, options) => {
1218
- if (!action || action === 'list') {
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({ frameworks: FRAMEWORKS });
1428
+ printJson(result);
1221
1429
  return;
1222
1430
  }
1223
1431
  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
- }
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
- 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
- };
1437
+ catch (err) {
1438
+ const message = err instanceof Error ? err.message : 'Oracle simulation failed';
1238
1439
  if (options.json) {
1239
- printJson(payload);
1440
+ printJson({ status: 'error', error: message });
1240
1441
  }
1241
1442
  else {
1242
1443
  console.log('');
1243
- console.log(theme.warning(` ${payload.message}`));
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
- // 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')
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
- // 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
- });
1469
+ printJson(result);
1312
1470
  return;
1313
1471
  }
1314
- // Interactive output
1315
- await PhantomDiscovery.autoRegisterAll();
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 (error) {
1318
- console.error(theme.error(' Failed to register agents:'), error);
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
- agentsCommand
1323
- .command('health')
1324
- .description('Check PHANTOM and agent connection health')
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
- // 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);
1502
+ printJson(result);
1360
1503
  return;
1361
1504
  }
1362
- // Interactive health check
1363
- await PhantomDiscovery.healthCheck();
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 (error) {
1366
- console.error(theme.error(' Health check failed:'), error);
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
- agentsCommand
1371
- .command('scan')
1372
- .description('Scan system for installed AI agents and LLMs')
1373
- .option('--register', 'Automatically register detected agents')
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 { 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 });
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
- 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
- }
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 : 'Agent scan failed';
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
- agentsCommand
1438
- .command('list')
1439
- .description('List registered agents and their integration status')
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
- const { AgentRegistry } = await import('@phantom/core');
1444
- const registry = new AgentRegistry();
1445
- const agents = registry.getAllAgents();
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({ agents });
1576
+ printJson(result);
1448
1577
  return;
1449
1578
  }
1450
1579
  console.log('');
1451
- console.log(theme.title(' REGISTERED AGENTS'));
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
- if (agents.length === 0) {
1454
- console.log(theme.warning(' No agents registered yet.'));
1455
- console.log(theme.dim(' Run: phantom agents scan'));
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
- program.parse(argv);
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