@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/README.md +14 -1
- package/dist/commands/chat.d.ts +6 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +342 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +14 -3
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/dashboard.d.ts +4 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +59 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/task.d.ts +4 -0
- package/dist/commands/task.d.ts.map +1 -0
- package/dist/commands/task.js +40 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/index.js +1209 -215
- package/dist/index.js.map +1 -1
- package/dist/postinstall.d.ts +3 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +22 -0
- package/dist/postinstall.js.map +1 -0
- package/package.json +21 -5
package/dist/index.js
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
// ╔══════════════════════════════════════════════════════════════════╗
|
|
4
|
+
// ║ PHANTOM CLI — "Follow the white rabbit." ║
|
|
5
|
+
// ║ ║
|
|
6
|
+
// ║ The command-line gateway to the Phantom PM Operating System. ║
|
|
7
|
+
// ║ Every `phantom` command starts here — chat, swarm, prd, ║
|
|
8
|
+
// ║ simulate, agents, mcp, and 17 module superpowers. ║
|
|
9
|
+
// ╚══════════════════════════════════════════════════════════════════╝
|
|
10
|
+
import { existsSync, readdirSync, statSync } from 'fs';
|
|
3
11
|
import { basename, join, resolve } from 'path';
|
|
4
12
|
import { Command } from 'commander';
|
|
5
13
|
import { PHANTOM_ASCII, PHANTOM_VERSION, TAGLINE, FRAMEWORKS, getConfig, getContextEngine, getModuleManager, getSwarm, KNOWN_INTEGRATION_TARGETS, isKnownIntegrationTarget, scanIntegrations as scanIntegrationTargets, connectIntegration as connectIntegrationTarget, doctorIntegrations, analyzeScreenPath, auditScreensPath, generateRealDocumentation, getRealProducts, getRuntimeHealth, runDeterministicSimulation, } from '@phantom-pm/core';
|
|
14
|
+
import { registerWithAllDetected, registerWithSpecificAgent, listRegistrationTargets, } from '@phantom-pm/core';
|
|
6
15
|
import { registerConfigCommands } from './commands/config.js';
|
|
7
16
|
import { registerStoriesCommands } from './commands/stories.js';
|
|
17
|
+
import { startChat } from './commands/chat.js';
|
|
18
|
+
import { TaskAnalyze } from './commands/task.js';
|
|
8
19
|
import { PhantomMCPServer, runStdioServer, PhantomDiscovery } from '@phantom-pm/mcp-server';
|
|
9
20
|
import { theme, box, runBootSequence, showFirstRunSetup, renderModuleInstall, renderModuleStore, renderSwarmResult, renderHealthDashboard, } from '@phantom-pm/tui';
|
|
10
21
|
const program = new Command();
|
|
@@ -27,6 +38,31 @@ function failNotImplemented(command) {
|
|
|
27
38
|
console.error('');
|
|
28
39
|
process.exitCode = 1;
|
|
29
40
|
}
|
|
41
|
+
function asObject(value) {
|
|
42
|
+
if (!value || typeof value !== 'object')
|
|
43
|
+
return {};
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
async function runModuleCommand(moduleName, moduleLabel, commandName, args) {
|
|
47
|
+
const moduleManager = getModuleManager();
|
|
48
|
+
if (!moduleManager.isInstalled(moduleName)) {
|
|
49
|
+
console.log('');
|
|
50
|
+
console.log(theme.warning(` ${moduleLabel} module not installed. Installing...`));
|
|
51
|
+
await moduleManager.install(moduleName);
|
|
52
|
+
}
|
|
53
|
+
const result = await moduleManager.executeCommand(moduleName, commandName, args);
|
|
54
|
+
return asObject(result);
|
|
55
|
+
}
|
|
56
|
+
function parseJsonOption(raw, optionName) {
|
|
57
|
+
if (!raw)
|
|
58
|
+
return undefined;
|
|
59
|
+
try {
|
|
60
|
+
return JSON.parse(raw);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
throw new Error(`Invalid JSON for ${optionName}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
30
66
|
program
|
|
31
67
|
.name('phantom')
|
|
32
68
|
.description(TAGLINE)
|
|
@@ -288,14 +324,80 @@ mcpCommand
|
|
|
288
324
|
mcpCommand
|
|
289
325
|
.command('serve')
|
|
290
326
|
.description('Run MCP server over stdio')
|
|
291
|
-
.option('--mode <mode>', '
|
|
327
|
+
.option('--mode <mode>', 'Transport mode (stdio, legacy-jsonl)', 'stdio')
|
|
328
|
+
.option('--tools <mode>', 'Tool loading mode (core, standard, all)', 'standard')
|
|
329
|
+
.action(async (options) => {
|
|
330
|
+
const transportMode = options.mode === 'legacy-jsonl' ? 'legacy-jsonl' : 'stdio';
|
|
331
|
+
if (options.mode !== 'stdio' && options.mode !== 'legacy-jsonl') {
|
|
332
|
+
console.log('');
|
|
333
|
+
console.log(theme.warning(` Unsupported transport mode '${options.mode}', using stdio.`));
|
|
334
|
+
console.log('');
|
|
335
|
+
}
|
|
336
|
+
// Validate tool mode
|
|
337
|
+
const validToolModes = ['core', 'standard', 'all'];
|
|
338
|
+
const toolMode = validToolModes.includes(options.tools) ? options.tools : 'standard';
|
|
339
|
+
if (!validToolModes.includes(options.tools)) {
|
|
340
|
+
console.log(theme.warning(` Unsupported tool mode '${options.tools}', using standard.`));
|
|
341
|
+
}
|
|
342
|
+
await runStdioServer(transportMode, toolMode);
|
|
343
|
+
});
|
|
344
|
+
mcpCommand
|
|
345
|
+
.command('status')
|
|
346
|
+
.description('Check MCP integration status')
|
|
347
|
+
.option('--json', 'Output as JSON')
|
|
292
348
|
.action(async (options) => {
|
|
293
|
-
|
|
349
|
+
const { PhantomDiscovery } = await import('@phantom-pm/mcp-server');
|
|
350
|
+
const report = await PhantomDiscovery.healthReport();
|
|
351
|
+
if (options.json) {
|
|
352
|
+
printJson(report);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
console.log('');
|
|
356
|
+
console.log(theme.title(' MCP INTEGRATION STATUS'));
|
|
357
|
+
console.log('');
|
|
358
|
+
// Check MCP server
|
|
359
|
+
const mcpRunning = report.mcp_server.status === 'running';
|
|
360
|
+
console.log(` ${theme.secondary('MCP Server:')} ${mcpRunning ? theme.success('Running') : theme.error('Not responding')}`);
|
|
361
|
+
// Check agent registrations
|
|
362
|
+
const agents = report.agents;
|
|
363
|
+
const installedAgents = agents.filter(agent => agent.installed);
|
|
364
|
+
if (installedAgents.length === 0) {
|
|
294
365
|
console.log('');
|
|
295
|
-
console.log(theme.warning(
|
|
366
|
+
console.log(theme.warning(' No AI agents detected on this system.'));
|
|
367
|
+
console.log(theme.dim(' Install Cursor, Codex, or other MCP-compatible editors to enable integration.'));
|
|
296
368
|
console.log('');
|
|
369
|
+
return;
|
|
297
370
|
}
|
|
298
|
-
|
|
371
|
+
console.log('');
|
|
372
|
+
console.log(theme.secondary(` Detected Agents (${installedAgents.length}):`));
|
|
373
|
+
for (const agent of installedAgents) {
|
|
374
|
+
const status = agent.registered ? theme.success('Registered') : theme.warning('Not registered');
|
|
375
|
+
console.log(` ${agent.name}: ${status}`);
|
|
376
|
+
}
|
|
377
|
+
console.log('');
|
|
378
|
+
if (mcpRunning && installedAgents.some(agent => agent.registered)) {
|
|
379
|
+
console.log(theme.success(' ✅ MCP integration is ready!'));
|
|
380
|
+
console.log(theme.dim(' Restart your AI agents to enable PHANTOM integration.'));
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
console.log(theme.warning(' ⚠️ MCP integration needs attention.'));
|
|
384
|
+
console.log(theme.dim(' Run "phantom mcp register" to register with agents.'));
|
|
385
|
+
}
|
|
386
|
+
console.log('');
|
|
387
|
+
});
|
|
388
|
+
mcpCommand
|
|
389
|
+
.command('register')
|
|
390
|
+
.description('Manually register with detected AI agents')
|
|
391
|
+
.action(async () => {
|
|
392
|
+
const { PhantomDiscovery } = await import('@phantom-pm/mcp-server');
|
|
393
|
+
console.log('');
|
|
394
|
+
console.log(theme.title(' MCP REGISTRATION'));
|
|
395
|
+
console.log('');
|
|
396
|
+
await PhantomDiscovery.autoRegisterAll();
|
|
397
|
+
console.log('');
|
|
398
|
+
console.log(theme.success(' Registration process completed!'));
|
|
399
|
+
console.log(theme.dim(' Restart your AI agents to enable PHANTOM integration.'));
|
|
400
|
+
console.log('');
|
|
299
401
|
});
|
|
300
402
|
program
|
|
301
403
|
.command('status')
|
|
@@ -392,6 +494,92 @@ program
|
|
|
392
494
|
}
|
|
393
495
|
console.log('');
|
|
394
496
|
});
|
|
497
|
+
program
|
|
498
|
+
.command('register')
|
|
499
|
+
.description('Register Phantom MCP server with detected AI agents')
|
|
500
|
+
.option('--target <agent>', 'Register with a specific agent (e.g. cursor, claude-code)')
|
|
501
|
+
.option('--all', 'Register with ALL detected agents')
|
|
502
|
+
.option('--list', 'List all registration targets and their status')
|
|
503
|
+
.option('--json', 'Output as JSON')
|
|
504
|
+
.action(async (options) => {
|
|
505
|
+
try {
|
|
506
|
+
const cwd = process.cwd();
|
|
507
|
+
if (options.list) {
|
|
508
|
+
const targets = listRegistrationTargets(cwd);
|
|
509
|
+
if (options.json) {
|
|
510
|
+
printJson({ targets });
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
console.log('');
|
|
514
|
+
console.log(theme.title(' MCP REGISTRATION TARGETS'));
|
|
515
|
+
console.log('');
|
|
516
|
+
for (const t of targets) {
|
|
517
|
+
const statusIcon = t.registered ? theme.success('✓ Registered') :
|
|
518
|
+
t.exists ? theme.warning('○ Not registered') :
|
|
519
|
+
theme.dim('— Config not found');
|
|
520
|
+
console.log(` ${theme.accent(t.agentName.padEnd(30))} ${statusIcon}`);
|
|
521
|
+
console.log(` ${theme.dim(t.configPath)}`);
|
|
522
|
+
console.log('');
|
|
523
|
+
}
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
if (options.target) {
|
|
527
|
+
const result = registerWithSpecificAgent(cwd, options.target);
|
|
528
|
+
if (options.json) {
|
|
529
|
+
printJson(result);
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
console.log('');
|
|
533
|
+
if (result.success) {
|
|
534
|
+
console.log(theme.success(` ✓ Phantom MCP registered with ${result.agentName}`));
|
|
535
|
+
console.log(` ${theme.secondary('Config:')} ${result.configPath}`);
|
|
536
|
+
console.log(` ${theme.secondary('Action:')} ${result.action}`);
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
console.log(theme.error(` ✗ Failed: ${result.message}`));
|
|
540
|
+
}
|
|
541
|
+
console.log('');
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
// Default: register with all detected agents
|
|
545
|
+
const summary = await registerWithAllDetected(cwd);
|
|
546
|
+
if (options.json) {
|
|
547
|
+
printJson(summary);
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
console.log('');
|
|
551
|
+
console.log(theme.title(' PHANTOM MCP AUTO-REGISTRATION'));
|
|
552
|
+
console.log('');
|
|
553
|
+
for (const result of summary.results) {
|
|
554
|
+
const icon = result.success
|
|
555
|
+
? (result.action === 'skipped' ? '○' : '✓')
|
|
556
|
+
: '✗';
|
|
557
|
+
const color = result.success
|
|
558
|
+
? (result.action === 'skipped' ? theme.dim : theme.success)
|
|
559
|
+
: theme.error;
|
|
560
|
+
console.log(` ${color(`${icon} ${result.agentName}`)} — ${result.message}`);
|
|
561
|
+
}
|
|
562
|
+
console.log('');
|
|
563
|
+
console.log(theme.secondary(` Total: ${summary.totalTargets} | Registered: ${summary.successful} | Skipped: ${summary.skipped} | Errors: ${summary.errors}`));
|
|
564
|
+
if (summary.successful > 0) {
|
|
565
|
+
console.log('');
|
|
566
|
+
console.log(theme.success(' Restart your AI agents to activate Phantom integration.'));
|
|
567
|
+
}
|
|
568
|
+
console.log('');
|
|
569
|
+
}
|
|
570
|
+
catch (err) {
|
|
571
|
+
const message = err instanceof Error ? err.message : 'Registration failed';
|
|
572
|
+
if (options.json) {
|
|
573
|
+
printJson({ status: 'error', error: message });
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
console.log('');
|
|
577
|
+
console.log(theme.error(` ${message}`));
|
|
578
|
+
console.log('');
|
|
579
|
+
}
|
|
580
|
+
process.exitCode = 1;
|
|
581
|
+
}
|
|
582
|
+
});
|
|
395
583
|
const prdCommand = program.command('prd').description('PRD operations');
|
|
396
584
|
// Register config commands
|
|
397
585
|
registerConfigCommands(program);
|
|
@@ -419,9 +607,9 @@ prdCommand
|
|
|
419
607
|
technical: options.technical,
|
|
420
608
|
ux: options.ux,
|
|
421
609
|
metrics: options.metrics,
|
|
422
|
-
output: options.out || '
|
|
610
|
+
output: options.out || './.phantom/output/prds',
|
|
423
611
|
});
|
|
424
|
-
const outputPath = result.prd.filePath || '
|
|
612
|
+
const outputPath = result.prd.filePath || './.phantom/output/prds';
|
|
425
613
|
const payload = {
|
|
426
614
|
status: 'ok',
|
|
427
615
|
module: 'prd-forge',
|
|
@@ -456,10 +644,10 @@ prdCommand
|
|
|
456
644
|
});
|
|
457
645
|
prdCommand
|
|
458
646
|
.command('list')
|
|
459
|
-
.description('List generated PRDs from phantom
|
|
647
|
+
.description('List generated PRDs from .phantom/output/prds directory')
|
|
460
648
|
.option('--json', 'Output as JSON')
|
|
461
649
|
.action((options) => {
|
|
462
|
-
const outDir = join(process.cwd(), 'phantom
|
|
650
|
+
const outDir = join(process.cwd(), '.phantom', 'output', 'prds');
|
|
463
651
|
const items = existsSync(outDir)
|
|
464
652
|
? readdirSync(outDir)
|
|
465
653
|
.filter(file => file.endsWith('.md'))
|
|
@@ -481,7 +669,7 @@ prdCommand
|
|
|
481
669
|
console.log(theme.title(' PRD LIBRARY'));
|
|
482
670
|
console.log('');
|
|
483
671
|
if (items.length === 0) {
|
|
484
|
-
console.log(theme.warning(' No PRDs found in phantom
|
|
672
|
+
console.log(theme.warning(' No PRDs found in .phantom/output/prds/.'));
|
|
485
673
|
}
|
|
486
674
|
else {
|
|
487
675
|
for (const item of items) {
|
|
@@ -515,9 +703,18 @@ program
|
|
|
515
703
|
console.log(theme.error(` ${message}`));
|
|
516
704
|
console.log('');
|
|
517
705
|
}
|
|
518
|
-
process.exitCode = 1;
|
|
519
706
|
}
|
|
520
707
|
});
|
|
708
|
+
program
|
|
709
|
+
.command('task')
|
|
710
|
+
.description('Deep task analysis and decomposition')
|
|
711
|
+
.command('analyze <goal>')
|
|
712
|
+
.description('Recursively decompose a goal into subtasks')
|
|
713
|
+
.action(async (goal) => {
|
|
714
|
+
// We need to render the React component
|
|
715
|
+
const { render } = await import('ink');
|
|
716
|
+
render(_jsx(TaskAnalyze, { goal: goal }));
|
|
717
|
+
});
|
|
521
718
|
const screenCommand = program.command('screen').description('Screen analysis commands');
|
|
522
719
|
screenCommand
|
|
523
720
|
.command('analyze <path>')
|
|
@@ -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('
|
|
613
|
-
console.log(` ${theme.secondary('Scenario:')} ${
|
|
614
|
-
console.log(
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
-
|
|
1182
|
-
|
|
1183
|
-
.
|
|
1184
|
-
.
|
|
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
|
|
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(
|
|
1413
|
+
printJson(result);
|
|
1191
1414
|
return;
|
|
1192
1415
|
}
|
|
1193
1416
|
console.log('');
|
|
1194
|
-
console.log(theme.success('
|
|
1195
|
-
|
|
1196
|
-
|
|
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 : '
|
|
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
|
-
|
|
1214
|
-
.command('
|
|
1215
|
-
.description('
|
|
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((
|
|
1218
|
-
|
|
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(
|
|
1449
|
+
printJson(result);
|
|
1221
1450
|
return;
|
|
1222
1451
|
}
|
|
1223
1452
|
console.log('');
|
|
1224
|
-
console.log(theme.
|
|
1225
|
-
console.log('');
|
|
1226
|
-
|
|
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
|
-
|
|
1233
|
-
const
|
|
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(
|
|
1461
|
+
printJson({ status: 'error', error: message });
|
|
1240
1462
|
}
|
|
1241
1463
|
else {
|
|
1242
1464
|
console.log('');
|
|
1243
|
-
console.log(theme.
|
|
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
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
.
|
|
1288
|
-
.
|
|
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
|
-
|
|
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
|
-
|
|
1315
|
-
|
|
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 (
|
|
1318
|
-
|
|
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
|
-
|
|
1323
|
-
.command('
|
|
1324
|
-
.description('
|
|
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
|
-
|
|
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
|
-
|
|
1363
|
-
|
|
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 (
|
|
1366
|
-
|
|
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
|
-
|
|
1371
|
-
|
|
1372
|
-
.
|
|
1373
|
-
.
|
|
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
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
printJson({ detected: agents, registered: registered.map(r => r.id) });
|
|
1385
|
-
return;
|
|
1386
|
-
}
|
|
1387
|
-
console.log('');
|
|
1388
|
-
console.log(theme.success(` Registered ${registered.length} new agents:`));
|
|
1389
|
-
for (const agent of registered) {
|
|
1390
|
-
console.log(` • ${agent.signature.name}`);
|
|
1391
|
-
}
|
|
1392
|
-
console.log('');
|
|
1393
|
-
}
|
|
1394
|
-
if (options.json && !options.register) {
|
|
1395
|
-
printJson({ agents });
|
|
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
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
console.log(theme.warning(' No AI agents detected in your system.'));
|
|
1404
|
-
console.log(theme.dim(' Supported: Claude Code, Cursor, Codex, Gemini, ChatGPT, VS Code, Zed'));
|
|
1405
|
-
console.log('');
|
|
1406
|
-
return;
|
|
1407
|
-
}
|
|
1408
|
-
for (const agent of agents) {
|
|
1409
|
-
const statusIcon = agent.status === 'running' ? '🟢' : '🔵';
|
|
1410
|
-
const confidenceColor = agent.confidence > 80 ? theme.success :
|
|
1411
|
-
agent.confidence > 60 ? theme.warning : theme.dim;
|
|
1412
|
-
console.log(` ${statusIcon} ${theme.accent(agent.signature.name)}`);
|
|
1413
|
-
console.log(` ${theme.secondary(agent.signature.description)}`);
|
|
1414
|
-
console.log(` ${confidenceColor(`Confidence: ${agent.confidence}%`)} | Status: ${agent.status}`);
|
|
1415
|
-
if (agent.detectedPaths.length > 0) {
|
|
1416
|
-
console.log(` ${theme.dim(`Paths: ${agent.detectedPaths.join(', ')}`)}`);
|
|
1417
|
-
}
|
|
1418
|
-
console.log('');
|
|
1419
|
-
}
|
|
1420
|
-
console.log(theme.dim(' Run with --register to automatically register detected agents'));
|
|
1421
|
-
console.log('');
|
|
1422
|
-
}
|
|
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 : '
|
|
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
|
-
|
|
1438
|
-
.command('
|
|
1439
|
-
.description('
|
|
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
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
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
|
-
|
|
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
|