@phantom-pm/cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1627 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
3
+ import { basename, join, resolve } from 'path';
4
+ import { Command } from 'commander';
5
+ 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';
6
+ import { registerConfigCommands } from './commands/config.js';
7
+ import { registerStoriesCommands } from './commands/stories.js';
8
+ import { PhantomMCPServer, runStdioServer, PhantomDiscovery } from '@phantom-pm/mcp-server';
9
+ import { theme, box, runBootSequence, showFirstRunSetup, renderModuleInstall, renderModuleStore, renderSwarmResult, renderHealthDashboard, } from '@phantom-pm/tui';
10
+ const program = new Command();
11
+ function printJson(payload) {
12
+ console.log(JSON.stringify(payload, null, 2));
13
+ }
14
+ function formatSize(bytes) {
15
+ if (bytes < 1024)
16
+ return `${bytes} B`;
17
+ if (bytes < 1024 * 1024)
18
+ return `${(bytes / 1024).toFixed(1)} KB`;
19
+ if (bytes < 1024 * 1024 * 1024)
20
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
21
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
22
+ }
23
+ function failNotImplemented(command) {
24
+ console.error('');
25
+ console.error(theme.error(` ${command} is not implemented in real runtime mode.`));
26
+ console.error(theme.secondary(' Use implemented commands: status, doctor, context, swarm, screen, health, docs, integrate, mcp.'));
27
+ console.error('');
28
+ process.exitCode = 1;
29
+ }
30
+ program
31
+ .name('phantom')
32
+ .description(TAGLINE)
33
+ .version(PHANTOM_VERSION, '-v, --version')
34
+ .action(async () => {
35
+ const config = getConfig();
36
+ if (config.isFirstRun()) {
37
+ await runBootSequence();
38
+ await showFirstRunSetup();
39
+ config.completeFirstRun();
40
+ return;
41
+ }
42
+ const cfg = config.get();
43
+ const stats = getContextEngine().getStats();
44
+ const lines = [
45
+ '',
46
+ ` ${theme.secondary('Version:')} ${PHANTOM_VERSION}`,
47
+ ` ${theme.secondary('Active project:')} ${cfg.activeProject || 'none'}`,
48
+ ` ${theme.secondary('Context files:')} ${stats.totalFiles}`,
49
+ ` ${theme.secondary('Installed modules:')} ${cfg.installedModules.length}`,
50
+ ` ${theme.secondary('Integrations:')} ${cfg.integrations.length}`,
51
+ '',
52
+ ` ${theme.dim('Try: phantom --help')}`,
53
+ '',
54
+ ];
55
+ console.log('');
56
+ console.log(theme.green(PHANTOM_ASCII));
57
+ console.log(box(lines.join('\n'), TAGLINE, 60));
58
+ });
59
+ const contextCommand = program.command('context').description('Manage product context');
60
+ contextCommand
61
+ .command('add <path>')
62
+ .description('Add project files into deterministic local context index')
63
+ .option('--json', 'Output as JSON')
64
+ .action(async (targetPath, options) => {
65
+ const resolvedPath = resolve(targetPath);
66
+ const contextEngine = getContextEngine();
67
+ try {
68
+ const stats = await contextEngine.addPath(resolvedPath);
69
+ const config = getConfig();
70
+ config.addProject({
71
+ name: basename(resolvedPath) || 'project',
72
+ path: resolvedPath,
73
+ contextPaths: [resolvedPath],
74
+ createdAt: new Date().toISOString(),
75
+ lastAccessed: new Date().toISOString(),
76
+ });
77
+ if (options.json) {
78
+ printJson({ path: resolvedPath, stats });
79
+ return;
80
+ }
81
+ console.log('');
82
+ console.log(theme.success(' Context ingested successfully.'));
83
+ console.log(` ${theme.secondary('Path:')} ${resolvedPath}`);
84
+ console.log(` ${theme.secondary('Files indexed:')} ${stats.totalFiles}`);
85
+ console.log(` ${theme.secondary('Total size:')} ${formatSize(stats.totalSize)}`);
86
+ console.log(` ${theme.secondary('Health score:')} ${stats.healthScore}%`);
87
+ console.log('');
88
+ }
89
+ catch (err) {
90
+ const message = err instanceof Error ? err.message : 'Unknown context indexing error';
91
+ if (options.json) {
92
+ printJson({ status: 'error', error: message });
93
+ }
94
+ else {
95
+ console.log('');
96
+ console.log(theme.error(` ${message}`));
97
+ console.log('');
98
+ }
99
+ process.exitCode = 1;
100
+ }
101
+ });
102
+ contextCommand
103
+ .description('Show active project context')
104
+ .option('--json', 'Output as JSON')
105
+ .action((options) => {
106
+ const config = getConfig();
107
+ const project = config.getActiveProject();
108
+ const stats = getContextEngine().getStats();
109
+ const payload = {
110
+ activeProject: project || null,
111
+ contextStats: stats,
112
+ };
113
+ if (options.json) {
114
+ printJson(payload);
115
+ return;
116
+ }
117
+ console.log('');
118
+ if (!project) {
119
+ console.log(theme.warning(' No active project. Add context first: phantom context add ./path'));
120
+ console.log('');
121
+ return;
122
+ }
123
+ console.log(theme.title(' PRODUCT CONTEXT'));
124
+ console.log(` ${theme.secondary('Project:')} ${project.name}`);
125
+ console.log(` ${theme.secondary('Path:')} ${project.path}`);
126
+ console.log(` ${theme.secondary('Indexed files:')} ${stats.totalFiles}`);
127
+ console.log(` ${theme.secondary('Health score:')} ${stats.healthScore}%`);
128
+ console.log('');
129
+ });
130
+ program
131
+ .command('install <module>')
132
+ .description('Install a built-in Phantom module')
133
+ .option('--json', 'Output as JSON')
134
+ .action(async (moduleName, options) => {
135
+ try {
136
+ const mm = getModuleManager();
137
+ const mod = await mm.install(moduleName);
138
+ if (options.json) {
139
+ printJson({ status: 'ok', module: mod });
140
+ return;
141
+ }
142
+ await renderModuleInstall(mod);
143
+ }
144
+ catch (err) {
145
+ const message = err instanceof Error ? err.message : 'Failed to install module';
146
+ if (options.json) {
147
+ printJson({ status: 'error', error: message });
148
+ }
149
+ else {
150
+ console.log('');
151
+ console.log(theme.error(` ${message}`));
152
+ console.log('');
153
+ }
154
+ process.exitCode = 1;
155
+ }
156
+ });
157
+ program
158
+ .command('modules')
159
+ .alias('store')
160
+ .description('Browse built-in module registry')
161
+ .option('--json', 'Output as JSON')
162
+ .action((options) => {
163
+ const mm = getModuleManager();
164
+ const config = getConfig();
165
+ const payload = {
166
+ available: mm.getAvailableModules(),
167
+ installed: config.get().installedModules,
168
+ };
169
+ if (options.json) {
170
+ printJson(payload);
171
+ return;
172
+ }
173
+ console.log(renderModuleStore(payload.available, payload.installed));
174
+ });
175
+ const integrateCommand = program.command('integrate').description('Integration operations');
176
+ function connectIntegrationAndPrint(target, options) {
177
+ const normalized = target.toLowerCase();
178
+ if (!isKnownIntegrationTarget(normalized)) {
179
+ const error = `Unsupported integration target: ${target}`;
180
+ if (options.json) {
181
+ printJson({ status: 'error', error, supported: KNOWN_INTEGRATION_TARGETS });
182
+ }
183
+ else {
184
+ console.log('');
185
+ console.log(theme.error(` ${error}`));
186
+ console.log(` ${theme.secondary(`Supported: ${KNOWN_INTEGRATION_TARGETS.join(', ')}`)}`);
187
+ console.log('');
188
+ }
189
+ process.exitCode = 1;
190
+ return;
191
+ }
192
+ const connected = connectIntegrationTarget(normalized, process.cwd());
193
+ if (options.json) {
194
+ printJson({ status: 'ok', integration: connected });
195
+ return;
196
+ }
197
+ console.log('');
198
+ console.log(theme.success(` Integration connected: ${connected.name}`));
199
+ if (connected.detectedPath) {
200
+ console.log(` ${theme.secondary('Detected at:')} ${connected.detectedPath}`);
201
+ }
202
+ console.log('');
203
+ }
204
+ integrateCommand
205
+ .command('scan')
206
+ .description('Scan workspace for integration signals')
207
+ .option('--json', 'Output as JSON')
208
+ .action((options) => {
209
+ const scan = scanIntegrationTargets(process.cwd());
210
+ if (options.json) {
211
+ printJson({ integrations: scan });
212
+ return;
213
+ }
214
+ console.log('');
215
+ console.log(theme.title(' INTEGRATION SCAN'));
216
+ console.log('');
217
+ for (const item of scan) {
218
+ const mark = item.detected ? theme.check : theme.warning_icon;
219
+ console.log(` ${mark} ${item.target} ${theme.dim(`(${item.reason})`)}`);
220
+ if (item.detectedPath)
221
+ console.log(` ${theme.dim(item.detectedPath)}`);
222
+ }
223
+ console.log('');
224
+ });
225
+ integrateCommand
226
+ .command('doctor')
227
+ .description('Validate configured integrations')
228
+ .option('--json', 'Output as JSON')
229
+ .action((options) => {
230
+ const checks = doctorIntegrations(process.cwd());
231
+ if (options.json) {
232
+ printJson({ checks });
233
+ return;
234
+ }
235
+ console.log('');
236
+ console.log(theme.title(' INTEGRATION DOCTOR'));
237
+ console.log('');
238
+ for (const check of checks.filter(c => c.configured || c.detected)) {
239
+ const mark = check.healthy ? theme.check : theme.warning_icon;
240
+ console.log(` ${mark} ${check.target} ${theme.dim(`(${check.reason})`)}`);
241
+ if (check.detectedPath)
242
+ console.log(` ${theme.dim(check.detectedPath)}`);
243
+ }
244
+ if (!checks.some(c => c.configured || c.detected)) {
245
+ console.log(theme.warning(' No integration signals or configured targets yet.'));
246
+ }
247
+ console.log('');
248
+ });
249
+ integrateCommand
250
+ .command('connect <target>')
251
+ .description('Connect a specific integration target')
252
+ .option('--json', 'Output as JSON')
253
+ .action((target, options) => {
254
+ connectIntegrationAndPrint(target, options);
255
+ });
256
+ integrateCommand
257
+ .description('Show integration usage')
258
+ .action(() => {
259
+ console.log('');
260
+ console.log(` ${theme.secondary('Usage:')}`);
261
+ console.log(` ${theme.accent('phantom integrate scan --json')}`);
262
+ console.log(` ${theme.accent('phantom integrate connect github --json')}`);
263
+ console.log(` ${theme.accent('phantom integrate doctor --json')}`);
264
+ console.log(` ${theme.accent('phantom integrate github --json')}`);
265
+ console.log('');
266
+ });
267
+ const mcpCommand = program.command('mcp').description('MCP server commands');
268
+ mcpCommand
269
+ .command('tools')
270
+ .description('List supported MCP tools')
271
+ .option('--json', 'Output as JSON')
272
+ .action((options) => {
273
+ const server = new PhantomMCPServer();
274
+ const tools = server.listTools();
275
+ if (options.json) {
276
+ printJson({ tools });
277
+ return;
278
+ }
279
+ console.log('');
280
+ console.log(theme.title(' MCP TOOLS'));
281
+ console.log('');
282
+ for (const tool of tools) {
283
+ console.log(` ${theme.check} ${tool.name}`);
284
+ console.log(` ${theme.dim(tool.description)}`);
285
+ }
286
+ console.log('');
287
+ });
288
+ mcpCommand
289
+ .command('serve')
290
+ .description('Run MCP server over stdio')
291
+ .option('--mode <mode>', 'transport mode', 'stdio')
292
+ .action(async (options) => {
293
+ if (options.mode !== 'stdio') {
294
+ console.log('');
295
+ console.log(theme.warning(` Unsupported mode '${options.mode}', using stdio.`));
296
+ console.log('');
297
+ }
298
+ await runStdioServer();
299
+ });
300
+ program
301
+ .command('status')
302
+ .description('Show Phantom runtime status')
303
+ .option('--json', 'Output as JSON')
304
+ .action((options) => {
305
+ const cfgMgr = getConfig();
306
+ const cfg = cfgMgr.get();
307
+ const payload = {
308
+ version: PHANTOM_VERSION,
309
+ firstRun: cfg.firstRun,
310
+ activeProject: cfgMgr.getActiveProject() || null,
311
+ installedModules: cfg.installedModules,
312
+ integrations: cfg.integrations,
313
+ dataMode: cfg.dataMode,
314
+ permissionLevel: cfg.permissionLevel,
315
+ theme: cfg.theme,
316
+ installation: cfg.installation,
317
+ mcp: cfg.mcp,
318
+ security: cfg.security,
319
+ };
320
+ if (options.json) {
321
+ printJson(payload);
322
+ return;
323
+ }
324
+ console.log('');
325
+ console.log(theme.title(' PHANTOM STATUS'));
326
+ console.log(` ${theme.secondary('Version:')} ${payload.version}`);
327
+ console.log(` ${theme.secondary('Active Project:')} ${payload.activeProject?.name || 'none'}`);
328
+ console.log(` ${theme.secondary('Installed Modules:')} ${payload.installedModules.length}`);
329
+ console.log(` ${theme.secondary('Integrations:')} ${payload.integrations.length}`);
330
+ console.log('');
331
+ });
332
+ program
333
+ .command('doctor')
334
+ .description('Run local environment and Phantom health checks')
335
+ .option('--json', 'Output as JSON')
336
+ .action((options) => {
337
+ const cfgMgr = getConfig();
338
+ const cfg = cfgMgr.get();
339
+ const checks = [
340
+ {
341
+ name: 'Config directory',
342
+ ok: existsSync(cfgMgr.getConfigDir()),
343
+ detail: cfgMgr.getConfigDir(),
344
+ },
345
+ {
346
+ name: 'Context entries present',
347
+ ok: getContextEngine().getEntries().length > 0,
348
+ detail: `${getContextEngine().getEntries().length}`,
349
+ },
350
+ {
351
+ name: 'CLI build artifact',
352
+ ok: existsSync(join(process.cwd(), 'packages/cli/dist/index.js')),
353
+ detail: 'packages/cli/dist/index.js',
354
+ },
355
+ {
356
+ name: 'Config schema keys',
357
+ ok: typeof cfg.installation.channel === 'string' &&
358
+ typeof cfg.installation.version === 'string' &&
359
+ typeof cfg.mcp.enabled === 'boolean' &&
360
+ typeof cfg.mcp.server_mode === 'string' &&
361
+ Array.isArray(cfg.integrations) &&
362
+ typeof cfg.security.audit_log_path === 'string',
363
+ detail: 'installation/mcp/integrations/security',
364
+ },
365
+ ];
366
+ const passCount = checks.filter(c => c.ok).length;
367
+ const payload = {
368
+ checks,
369
+ summary: {
370
+ passing: passCount,
371
+ total: checks.length,
372
+ healthy: passCount === checks.length,
373
+ },
374
+ };
375
+ if (options.json) {
376
+ printJson(payload);
377
+ return;
378
+ }
379
+ console.log('');
380
+ console.log(theme.title(' PHANTOM DOCTOR'));
381
+ console.log('');
382
+ for (const check of checks) {
383
+ const icon = check.ok ? theme.check : theme.warning_icon;
384
+ console.log(` ${icon} ${check.name.padEnd(26)} ${theme.dim(check.detail)}`);
385
+ }
386
+ console.log('');
387
+ if (payload.summary.healthy) {
388
+ console.log(theme.success(` All checks passed (${passCount}/${checks.length}).`));
389
+ }
390
+ else {
391
+ console.log(theme.warning(` Some checks need attention (${passCount}/${checks.length}).`));
392
+ }
393
+ console.log('');
394
+ });
395
+ const prdCommand = program.command('prd').description('PRD operations');
396
+ // Register config commands
397
+ registerConfigCommands(program);
398
+ // Register stories commands
399
+ registerStoriesCommands(program);
400
+ prdCommand
401
+ .command('create <title>')
402
+ .description('Generate AI-powered PRD from title + local context')
403
+ .option('--out <path>', 'Output file path')
404
+ .option('--json', 'Output as JSON')
405
+ .option('--technical', 'Include technical requirements')
406
+ .option('--ux', 'Include UX wireframe descriptions')
407
+ .option('--metrics', 'Include metrics framework')
408
+ .action(async (title, options) => {
409
+ try {
410
+ const moduleManager = getModuleManager();
411
+ // Ensure prd-forge module is installed
412
+ if (!moduleManager.isInstalled('prd-forge')) {
413
+ console.log('');
414
+ console.log(theme.warning(' PRD Forge module not installed. Installing...'));
415
+ await moduleManager.install('prd-forge');
416
+ }
417
+ const result = await moduleManager.executeCommand('prd-forge', 'prd create', {
418
+ title,
419
+ technical: options.technical,
420
+ ux: options.ux,
421
+ metrics: options.metrics,
422
+ output: options.out || './phantom-output/prds',
423
+ });
424
+ const outputPath = result.prd.filePath || './phantom-output/prds';
425
+ const payload = {
426
+ status: 'ok',
427
+ module: 'prd-forge',
428
+ prd: result.prd,
429
+ metadata: result.metadata,
430
+ };
431
+ if (options.json) {
432
+ printJson(payload);
433
+ return;
434
+ }
435
+ console.log('');
436
+ console.log(theme.success(` PRD generated: ${result.prd.title}`));
437
+ console.log(` ${theme.secondary('ID:')} ${result.prd.id}`);
438
+ console.log(` ${theme.secondary('Sections:')} ${result.prd.sections.length}`);
439
+ console.log(` ${theme.secondary('Model:')} ${result.metadata.model}`);
440
+ console.log(` ${theme.secondary('Tokens:')} ${result.metadata.tokenCount}`);
441
+ console.log(` ${theme.secondary('Output:')} ${outputPath}`);
442
+ console.log('');
443
+ }
444
+ catch (err) {
445
+ const message = err instanceof Error ? err.message : 'Failed to generate PRD';
446
+ if (options.json) {
447
+ printJson({ status: 'error', error: message });
448
+ }
449
+ else {
450
+ console.log('');
451
+ console.log(theme.error(` ${message}`));
452
+ console.log('');
453
+ }
454
+ process.exitCode = 1;
455
+ }
456
+ });
457
+ prdCommand
458
+ .command('list')
459
+ .description('List generated PRDs from phantom-output directory')
460
+ .option('--json', 'Output as JSON')
461
+ .action((options) => {
462
+ const outDir = join(process.cwd(), 'phantom-output');
463
+ const items = existsSync(outDir)
464
+ ? readdirSync(outDir)
465
+ .filter(file => file.endsWith('.md'))
466
+ .map(file => {
467
+ const path = join(outDir, file);
468
+ return {
469
+ name: file,
470
+ path,
471
+ sizeBytes: statSync(path).size,
472
+ };
473
+ })
474
+ .sort((a, b) => a.name.localeCompare(b.name))
475
+ : [];
476
+ if (options.json) {
477
+ printJson({ files: items });
478
+ return;
479
+ }
480
+ console.log('');
481
+ console.log(theme.title(' PRD LIBRARY'));
482
+ console.log('');
483
+ if (items.length === 0) {
484
+ console.log(theme.warning(' No PRDs found in phantom-output/.'));
485
+ }
486
+ else {
487
+ for (const item of items) {
488
+ console.log(` ${theme.check} ${item.name} ${theme.dim(`(${formatSize(item.sizeBytes)})`)}`);
489
+ }
490
+ }
491
+ console.log('');
492
+ });
493
+ program
494
+ .command('swarm <question>')
495
+ .description('Run deterministic multi-agent product analysis')
496
+ .option('--json', 'Output as JSON')
497
+ .action(async (question, options) => {
498
+ try {
499
+ const result = await getSwarm().runSwarm(question);
500
+ if (options.json) {
501
+ printJson(result);
502
+ return;
503
+ }
504
+ console.log(renderSwarmResult(result));
505
+ console.log(` ${theme.dim(`Evidence count: ${result.evidence.length}`)}`);
506
+ console.log('');
507
+ }
508
+ catch (err) {
509
+ const message = err instanceof Error ? err.message : 'Swarm analysis failed';
510
+ if (options.json) {
511
+ printJson({ status: 'error', error: message });
512
+ }
513
+ else {
514
+ console.log('');
515
+ console.log(theme.error(` ${message}`));
516
+ console.log('');
517
+ }
518
+ process.exitCode = 1;
519
+ }
520
+ });
521
+ const screenCommand = program.command('screen').description('Screen analysis commands');
522
+ screenCommand
523
+ .command('analyze <path>')
524
+ .description('Analyze a single screenshot with deterministic UX checks')
525
+ .option('--json', 'Output as JSON')
526
+ .action((targetPath, options) => {
527
+ try {
528
+ const analysis = analyzeScreenPath(targetPath);
529
+ if (options.json) {
530
+ printJson(analysis);
531
+ return;
532
+ }
533
+ console.log('');
534
+ console.log(theme.title(` SCREEN ANALYSIS: ${analysis.filename}`));
535
+ console.log(` ${theme.secondary('Path:')} ${analysis.path}`);
536
+ console.log(` ${theme.secondary('Score:')} ${analysis.score}/100`);
537
+ console.log(` ${theme.secondary('Components detected:')} ${analysis.componentsDetected}`);
538
+ for (const issue of analysis.issues) {
539
+ console.log(` ${theme.warning_icon} ${issue.severity} ${issue.message}`);
540
+ }
541
+ console.log('');
542
+ }
543
+ catch (err) {
544
+ const message = err instanceof Error ? err.message : 'Screen analysis failed';
545
+ if (options.json) {
546
+ printJson({ status: 'error', error: message });
547
+ }
548
+ else {
549
+ console.log('');
550
+ console.log(theme.error(` ${message}`));
551
+ console.log('');
552
+ }
553
+ process.exitCode = 1;
554
+ }
555
+ });
556
+ screenCommand
557
+ .command('audit [path]')
558
+ .description('Audit one image or image directory')
559
+ .option('--json', 'Output as JSON')
560
+ .action((targetPath, options) => {
561
+ try {
562
+ const audit = auditScreensPath(targetPath || join(process.cwd(), 'screenshots'));
563
+ if (options.json) {
564
+ printJson(audit);
565
+ return;
566
+ }
567
+ console.log('');
568
+ console.log(theme.title(' SCREEN AUDIT'));
569
+ console.log(` ${theme.secondary('Files analyzed:')} ${audit.filesAnalyzed}`);
570
+ console.log(` ${theme.secondary('Overall score:')} ${audit.overallScore}/100`);
571
+ console.log(` ${theme.secondary('Issues:')} HIGH=${audit.issuesBySeverity.HIGH} MED=${audit.issuesBySeverity.MED} LOW=${audit.issuesBySeverity.LOW}`);
572
+ console.log('');
573
+ }
574
+ catch (err) {
575
+ const message = err instanceof Error ? err.message : 'Screen audit failed';
576
+ if (options.json) {
577
+ printJson({ status: 'error', error: message });
578
+ }
579
+ else {
580
+ console.log('');
581
+ console.log(theme.error(` ${message}`));
582
+ console.log('');
583
+ }
584
+ process.exitCode = 1;
585
+ }
586
+ });
587
+ program
588
+ .command('health')
589
+ .description('Show real runtime health metrics')
590
+ .option('--json', 'Output as JSON')
591
+ .action((options) => {
592
+ const data = getRuntimeHealth(process.cwd());
593
+ if (options.json) {
594
+ printJson(data);
595
+ return;
596
+ }
597
+ console.log('');
598
+ console.log(renderHealthDashboard(data));
599
+ console.log('');
600
+ });
601
+ program
602
+ .command('simulate <scenario>')
603
+ .description('Run deterministic simulation for a product scenario')
604
+ .option('--json', 'Output as JSON')
605
+ .action((scenario, options) => {
606
+ const result = runDeterministicSimulation(scenario);
607
+ if (options.json) {
608
+ printJson(result);
609
+ return;
610
+ }
611
+ console.log('');
612
+ console.log(theme.title(' DETERMINISTIC SIMULATION'));
613
+ console.log(` ${theme.secondary('Scenario:')} ${result.scenario}`);
614
+ console.log(` ${theme.secondary('Seed:')} ${result.seed}`);
615
+ console.log(` ${theme.secondary('Baseline:')} ${result.metrics.baseline}`);
616
+ console.log(` ${theme.secondary('Projected:')} ${result.metrics.projected}`);
617
+ console.log(` ${theme.secondary('Delta (%):')} ${result.metrics.deltaPercent}`);
618
+ console.log(` ${theme.secondary('Confidence:')} ${result.metrics.confidence}%`);
619
+ console.log('');
620
+ });
621
+ program
622
+ .command('nudge')
623
+ .description('Show intelligent nudges and suggestions')
624
+ .option('--json', 'Output as JSON')
625
+ .option('--dismiss <id>', 'Dismiss a specific nudge')
626
+ .option('--snooze <id>', 'Snooze a nudge (minutes)')
627
+ .option('--refresh', 'Generate new nudges based on current context')
628
+ .action(async (options) => {
629
+ try {
630
+ const { NudgeEngine, getConfig, getContextEngine, getModuleManager } = await import('@phantom/core');
631
+ const engine = new NudgeEngine();
632
+ // Handle dismiss/snooze actions
633
+ if (options.dismiss) {
634
+ const success = engine.dismissNudge(options.dismiss);
635
+ if (options.json) {
636
+ printJson({ status: success ? 'ok' : 'error', action: 'dismiss', id: options.dismiss });
637
+ }
638
+ else if (success) {
639
+ console.log(theme.success(` Nudge dismissed: ${options.dismiss}`));
640
+ }
641
+ else {
642
+ console.log(theme.error(` Failed to dismiss nudge: ${options.dismiss}`));
643
+ }
644
+ return;
645
+ }
646
+ if (options.snooze) {
647
+ const [id, minutesStr] = options.snooze.split(':');
648
+ const minutes = parseInt(minutesStr || '60');
649
+ const success = engine.snoozeNudge(id, minutes);
650
+ if (options.json) {
651
+ printJson({ status: success ? 'ok' : 'error', action: 'snooze', id, minutes });
652
+ }
653
+ else if (success) {
654
+ console.log(theme.success(` Nudge snoozed for ${minutes} minutes: ${id}`));
655
+ }
656
+ else {
657
+ console.log(theme.error(` Failed to snooze nudge: ${id}`));
658
+ }
659
+ return;
660
+ }
661
+ // Generate new nudges if requested
662
+ if (options.refresh) {
663
+ const config = getConfig();
664
+ const cfg = config.get();
665
+ const context = getContextEngine();
666
+ const modules = getModuleManager();
667
+ const userContext = {
668
+ activeProject: cfg.activeProject || null,
669
+ installedModules: cfg.installedModules,
670
+ connectedAgents: [], // TODO: Get from registry
671
+ recentActions: [], // TODO: Track recent actions
672
+ currentDirectory: process.cwd(),
673
+ timeOfDay: new Date().getHours().toString(),
674
+ dayOfWeek: new Date().getDay().toString()
675
+ };
676
+ await engine.generateNudges(userContext);
677
+ }
678
+ // Get current nudges
679
+ const nudges = engine.getCurrentNudges();
680
+ const stats = engine.getNudgeStats();
681
+ if (options.json) {
682
+ printJson({ nudges, stats });
683
+ return;
684
+ }
685
+ console.log('');
686
+ console.log(theme.title(' INTELLIGENT NUDGES'));
687
+ console.log(theme.secondary(` Active: ${stats.active} | Total Generated: ${stats.totalGenerated}`));
688
+ console.log('');
689
+ if (nudges.length === 0) {
690
+ console.log(theme.success(' 🎉 No active nudges. Everything looks good!'));
691
+ console.log(theme.dim(' Run with --refresh to generate new contextual suggestions'));
692
+ console.log('');
693
+ return;
694
+ }
695
+ // Display nudges by priority
696
+ const priorityOrder = ['critical', 'high', 'medium', 'low'];
697
+ for (const priority of priorityOrder) {
698
+ const priorityNudges = nudges.filter(n => n.priority === priority);
699
+ if (priorityNudges.length === 0)
700
+ continue;
701
+ const priorityTitle = {
702
+ 'critical': '🚨 CRITICAL ALERTS',
703
+ 'high': '⚠️ HIGH PRIORITY',
704
+ 'medium': '💡 RECOMMENDATIONS',
705
+ 'low': '📢 SUGGESTIONS'
706
+ }[priority];
707
+ console.log(theme.title(` ${priorityTitle}`));
708
+ console.log('');
709
+ for (const nudge of priorityNudges) {
710
+ const typeIcon = {
711
+ 'suggestion': '💡',
712
+ 'warning': '⚠️',
713
+ 'opportunity': '✨',
714
+ 'insight': '🔮',
715
+ 'alert': '🚨'
716
+ }[nudge.type] || '📋';
717
+ console.log(` ${typeIcon} ${theme.accent(nudge.title)}`);
718
+ console.log(` ${nudge.message}`);
719
+ if (nudge.command) {
720
+ console.log(` ${theme.dim(`Command: ${nudge.command}`)}`);
721
+ }
722
+ if (nudge.suggestions.length > 0) {
723
+ console.log(` ${theme.dim('Suggestions:')} ${nudge.suggestions.join(' • ')}`);
724
+ }
725
+ console.log(` ${theme.dim(`ID: ${nudge.id} | ${new Date(nudge.timestamp).toLocaleString()}`)}`);
726
+ console.log('');
727
+ }
728
+ }
729
+ console.log(theme.dim(' Use: phantom nudge --dismiss <id> to dismiss a nudge'));
730
+ console.log(theme.dim(' Use: phantom nudge --snooze <id>:<minutes> to snooze'));
731
+ console.log(theme.dim(' Use: phantom nudge --refresh to generate new suggestions'));
732
+ console.log('');
733
+ }
734
+ catch (err) {
735
+ const message = err instanceof Error ? err.message : 'Nudge system error';
736
+ if (options.json) {
737
+ printJson({ status: 'error', error: message });
738
+ }
739
+ else {
740
+ console.log('');
741
+ console.log(theme.error(` ${message}`));
742
+ console.log('');
743
+ }
744
+ process.exitCode = 1;
745
+ }
746
+ });
747
+ program
748
+ .command('products')
749
+ .description('Show persisted project/product portfolio')
750
+ .option('--json', 'Output as JSON')
751
+ .action((options) => {
752
+ const products = getRealProducts(process.cwd());
753
+ if (options.json) {
754
+ printJson({ products });
755
+ return;
756
+ }
757
+ if (products.length === 0) {
758
+ console.log('');
759
+ console.log(theme.warning(' No products found. Add context with: phantom context add ./project'));
760
+ console.log('');
761
+ return;
762
+ }
763
+ const lines = products.map((p) => {
764
+ const status = p.active ? theme.success('active') : p.paused ? theme.warning('paused') : theme.dim('tracked');
765
+ return ` ${p.name.padEnd(28)} ${status} health=${p.health}% context_files=${p.contextFiles}`;
766
+ });
767
+ console.log('');
768
+ console.log(box(lines.join('\n'), 'PRODUCT PORTFOLIO', 80));
769
+ console.log('');
770
+ });
771
+ const docsCommand = program.command('docs').description('Documentation operations');
772
+ const sprintCommand = program.command('sprint').description('Sprint planning operations');
773
+ sprintCommand
774
+ .command('plan')
775
+ .description('Plan a new sprint')
776
+ .option('--goal <string>', 'Sprint goal')
777
+ .option('--duration <days>', 'Sprint duration in days', '14')
778
+ .option('--velocity <points>', 'Team velocity in story points')
779
+ .option('--backlog <path>', 'Path to backlog file')
780
+ .option('--json', 'Output as JSON')
781
+ .action(async (options) => {
782
+ try {
783
+ const moduleManager = getModuleManager();
784
+ // Ensure sprint-planner module is installed
785
+ if (!moduleManager.isInstalled('sprint-planner')) {
786
+ console.log('');
787
+ console.log(theme.warning(' Sprint Planner module not installed. Installing...'));
788
+ await moduleManager.install('sprint-planner');
789
+ }
790
+ const result = await moduleManager.executeCommand('sprint-planner', 'sprint plan', {
791
+ goal: options.goal,
792
+ duration: options.duration ? parseInt(options.duration) : undefined,
793
+ velocity: options.velocity ? parseInt(options.velocity) : undefined,
794
+ backlog: options.backlog,
795
+ _: ['plan'],
796
+ });
797
+ if (options.json) {
798
+ printJson(result);
799
+ return;
800
+ }
801
+ console.log('');
802
+ console.log(theme.success(' Sprint plan generated successfully!'));
803
+ console.log(` ${theme.secondary('Sprint:')} ${result.sprint.name}`);
804
+ console.log(` ${theme.secondary('Goal:')} ${result.sprint.goal}`);
805
+ console.log(` ${theme.secondary('Stories:')} ${result.sprint.stories}`);
806
+ console.log(` ${theme.secondary('Total Points:')} ${result.sprint.totalPoints}`);
807
+ console.log(` ${theme.secondary('Dates:')} ${result.sprint.startDate} to ${result.sprint.endDate}`);
808
+ console.log(` ${theme.secondary('Output:')} ${result.filePath}`);
809
+ console.log('');
810
+ }
811
+ catch (err) {
812
+ const message = err instanceof Error ? err.message : 'Failed to generate sprint plan';
813
+ if (options.json) {
814
+ printJson({ status: 'error', error: message });
815
+ }
816
+ else {
817
+ console.log('');
818
+ console.log(theme.error(` ${message}`));
819
+ console.log('');
820
+ }
821
+ process.exitCode = 1;
822
+ }
823
+ });
824
+ sprintCommand
825
+ .command('retro')
826
+ .description('Generate sprint retrospective')
827
+ .option('--sprint <path>', 'Path to sprint data file')
828
+ .option('--json', 'Output as JSON')
829
+ .action(async (options) => {
830
+ try {
831
+ const moduleManager = getModuleManager();
832
+ // Ensure sprint-planner module is installed
833
+ if (!moduleManager.isInstalled('sprint-planner')) {
834
+ console.log('');
835
+ console.log(theme.warning(' Sprint Planner module not installed. Installing...'));
836
+ await moduleManager.install('sprint-planner');
837
+ }
838
+ const result = await moduleManager.executeCommand('sprint-planner', 'sprint retro', {
839
+ sprint: options.sprint,
840
+ _: ['retro'],
841
+ });
842
+ if (options.json) {
843
+ printJson(result);
844
+ return;
845
+ }
846
+ console.log('');
847
+ console.log(theme.success(' Sprint retrospective generated successfully!'));
848
+ console.log(` ${theme.secondary('Type:')} ${result.type}`);
849
+ if (result.filePath) {
850
+ console.log(` ${theme.secondary('Output:')} ${result.filePath}`);
851
+ }
852
+ console.log('');
853
+ }
854
+ catch (err) {
855
+ const message = err instanceof Error ? err.message : 'Failed to generate sprint retrospective';
856
+ if (options.json) {
857
+ printJson({ status: 'error', error: message });
858
+ }
859
+ else {
860
+ console.log('');
861
+ console.log(theme.error(` ${message}`));
862
+ console.log('');
863
+ }
864
+ process.exitCode = 1;
865
+ }
866
+ });
867
+ sprintCommand
868
+ .description('Show sprint planning usage')
869
+ .action(() => {
870
+ console.log('');
871
+ console.log(theme.title(' SPRINT PLANNING'));
872
+ console.log(theme.secondary(' AI-powered sprint planning with velocity tracking'));
873
+ console.log('');
874
+ console.log(` ${theme.accent('phantom sprint plan --goal "Sprint Goal"')}`);
875
+ console.log(` ${theme.accent('phantom sprint plan --duration 10 --velocity 15')}`);
876
+ console.log(` ${theme.accent('phantom sprint retro --sprint ./sprint-data.json')}`);
877
+ console.log('');
878
+ });
879
+ const bridgeCommand = program.command('bridge').description('PM ↔ Dev translation operations');
880
+ bridgeCommand
881
+ .command('translate <intent>')
882
+ .description('Translate PM intent to technical tasks')
883
+ .option('--constraints <constraints>', 'Comma-separated constraints')
884
+ .option('--json', 'Output as JSON')
885
+ .action(async (intent, options) => {
886
+ try {
887
+ const moduleManager = getModuleManager();
888
+ // Ensure bridge module is installed
889
+ if (!moduleManager.isInstalled('bridge')) {
890
+ console.log('');
891
+ console.log(theme.warning(' Bridge module not installed. Installing...'));
892
+ await moduleManager.install('bridge');
893
+ }
894
+ const result = await moduleManager.executeCommand('bridge', 'bridge translate', {
895
+ intent,
896
+ constraints: options.constraints,
897
+ _: ['translate', intent],
898
+ });
899
+ if (options.json) {
900
+ printJson(result);
901
+ return;
902
+ }
903
+ console.log('');
904
+ console.log(theme.success(' Translation completed successfully!'));
905
+ console.log(` ${theme.secondary('Technical Tasks:')} ${result.translation.technicalTasks.length}`);
906
+ console.log(` ${theme.secondary('Acceptance Criteria:')} ${result.translation.acceptanceCriteria.length}`);
907
+ console.log(` ${theme.secondary('Risks Identified:')} ${result.translation.risks.length}`);
908
+ console.log('');
909
+ }
910
+ catch (err) {
911
+ const message = err instanceof Error ? err.message : 'Failed to translate PM intent';
912
+ if (options.json) {
913
+ printJson({ status: 'error', error: message });
914
+ }
915
+ else {
916
+ console.log('');
917
+ console.log(theme.error(` ${message}`));
918
+ console.log('');
919
+ }
920
+ process.exitCode = 1;
921
+ }
922
+ });
923
+ bridgeCommand
924
+ .command('spec <requirements>')
925
+ .description('Generate technical specification from requirements')
926
+ .option('--json', 'Output as JSON')
927
+ .action(async (requirements, options) => {
928
+ try {
929
+ const moduleManager = getModuleManager();
930
+ // Ensure bridge module is installed
931
+ if (!moduleManager.isInstalled('bridge')) {
932
+ console.log('');
933
+ console.log(theme.warning(' Bridge module not installed. Installing...'));
934
+ await moduleManager.install('bridge');
935
+ }
936
+ const result = await moduleManager.executeCommand('bridge', 'bridge spec', {
937
+ requirements,
938
+ _: ['spec', requirements],
939
+ });
940
+ if (options.json) {
941
+ printJson(result);
942
+ return;
943
+ }
944
+ console.log('');
945
+ console.log(theme.success(' Technical specification generated successfully!'));
946
+ console.log(` ${theme.secondary('Architecture:')} ${result.specification.architecture}`);
947
+ console.log(` ${theme.secondary('API Endpoints:')} ${result.specification.apiEndpoints.length}`);
948
+ console.log(` ${theme.secondary('Dependencies:')} ${result.specification.dependencies.length}`);
949
+ console.log('');
950
+ }
951
+ catch (err) {
952
+ const message = err instanceof Error ? err.message : 'Failed to generate technical specification';
953
+ if (options.json) {
954
+ printJson({ status: 'error', error: message });
955
+ }
956
+ else {
957
+ console.log('');
958
+ console.log(theme.error(` ${message}`));
959
+ console.log('');
960
+ }
961
+ process.exitCode = 1;
962
+ }
963
+ });
964
+ bridgeCommand
965
+ .description('Show bridge usage')
966
+ .action(() => {
967
+ console.log('');
968
+ console.log(theme.title(' BRIDGE TRANSLATION'));
969
+ console.log(theme.secondary(' Bidirectional PM ↔ Dev translation engine'));
970
+ console.log('');
971
+ console.log(` ${theme.accent('phantom bridge translate "Implement user authentication"')}`);
972
+ console.log(` ${theme.accent('phantom bridge spec "Authentication system with OAuth support"')}`);
973
+ console.log('');
974
+ });
975
+ // Add the new commands to the existing command structure
976
+ const competitiveCommand = program.command('competitive').description('Competitive analysis operations');
977
+ competitiveCommand
978
+ .command('analyze <subject>')
979
+ .description('Analyze competitors in a market space')
980
+ .option('--depth <level>', 'Analysis depth (brief|detailed|comprehensive)', 'detailed')
981
+ .option('--trends', 'Include market trends')
982
+ .option('--json', 'Output as JSON')
983
+ .action(async (subject, options) => {
984
+ try {
985
+ const moduleManager = getModuleManager();
986
+ // Ensure competitive module is installed
987
+ if (!moduleManager.isInstalled('competitive')) {
988
+ console.log('');
989
+ console.log(theme.warning(' Competitive Analysis module not installed. Installing...'));
990
+ await moduleManager.install('competitive');
991
+ }
992
+ const result = await moduleManager.executeCommand('competitive', 'competitive analyze', {
993
+ subject,
994
+ depth: options.depth,
995
+ trends: options.trends,
996
+ _: ['analyze', subject],
997
+ });
998
+ if (options.json) {
999
+ printJson(result);
1000
+ return;
1001
+ }
1002
+ console.log('');
1003
+ console.log(theme.success(' Competitive analysis completed successfully!'));
1004
+ console.log(` ${theme.secondary('Subject:')} ${result.analysis.subject}`);
1005
+ console.log(` ${theme.secondary('Competitors Found:')} ${result.analysis.competitorCount}`);
1006
+ console.log(` ${theme.secondary('Output:')} ${result.filePath}`);
1007
+ console.log('');
1008
+ }
1009
+ catch (err) {
1010
+ const message = err instanceof Error ? err.message : 'Failed to run competitive analysis';
1011
+ if (options.json) {
1012
+ printJson({ status: 'error', error: message });
1013
+ }
1014
+ else {
1015
+ console.log('');
1016
+ console.log(theme.error(` ${message}`));
1017
+ console.log('');
1018
+ }
1019
+ process.exitCode = 1;
1020
+ }
1021
+ });
1022
+ competitiveCommand
1023
+ .command('watch <competitor>')
1024
+ .description('Watch a competitor for updates')
1025
+ .option('--json', 'Output as JSON')
1026
+ .action(async (competitor, options) => {
1027
+ try {
1028
+ const moduleManager = getModuleManager();
1029
+ // Ensure competitive module is installed
1030
+ if (!moduleManager.isInstalled('competitive')) {
1031
+ console.log('');
1032
+ console.log(theme.warning(' Competitive Analysis module not installed. Installing...'));
1033
+ await moduleManager.install('competitive');
1034
+ }
1035
+ const result = await moduleManager.executeCommand('competitive', 'competitive watch', {
1036
+ competitor,
1037
+ _: ['watch', competitor],
1038
+ });
1039
+ if (options.json) {
1040
+ printJson(result);
1041
+ return;
1042
+ }
1043
+ console.log('');
1044
+ console.log(theme.success(' Competitor watch initiated!'));
1045
+ console.log(` ${theme.secondary('Competitor:')} ${result.competitor}`);
1046
+ console.log(` ${theme.secondary('Report:')} ${result.report}`);
1047
+ console.log('');
1048
+ }
1049
+ catch (err) {
1050
+ const message = err instanceof Error ? err.message : 'Failed to initiate competitor watch';
1051
+ if (options.json) {
1052
+ printJson({ status: 'error', error: message });
1053
+ }
1054
+ else {
1055
+ console.log('');
1056
+ console.log(theme.error(` ${message}`));
1057
+ console.log('');
1058
+ }
1059
+ process.exitCode = 1;
1060
+ }
1061
+ });
1062
+ competitiveCommand
1063
+ .description('Show competitive analysis usage')
1064
+ .action(() => {
1065
+ console.log('');
1066
+ console.log(theme.title(' COMPETITIVE ANALYSIS'));
1067
+ console.log(theme.secondary(' Monitor competitors and analyze market positioning'));
1068
+ console.log('');
1069
+ console.log(` ${theme.accent('phantom competitive analyze "project management software"')}`);
1070
+ console.log(` ${theme.accent('phantom competitive watch "Notion"')}`);
1071
+ console.log(` ${theme.accent('phantom competitive analyze "AI tools" --depth comprehensive')}`);
1072
+ console.log('');
1073
+ });
1074
+ const analyticsCommand = program.command('analytics').description('Analytics operations');
1075
+ analyticsCommand
1076
+ .command('dashboard')
1077
+ .description('Generate analytics dashboard')
1078
+ .option('--period <days>', 'Analysis period', 'last 30 days')
1079
+ .option('--categories <list>', 'Comma-separated metric categories')
1080
+ .option('--format <type>', 'Output format (json|markdown)', 'json')
1081
+ .option('--json', 'Output as JSON')
1082
+ .action(async (options) => {
1083
+ try {
1084
+ const moduleManager = getModuleManager();
1085
+ // Ensure analytics-lens module is installed
1086
+ if (!moduleManager.isInstalled('analytics-lens')) {
1087
+ console.log('');
1088
+ console.log(theme.warning(' Analytics Lens module not installed. Installing...'));
1089
+ await moduleManager.install('analytics-lens');
1090
+ }
1091
+ const result = await moduleManager.executeCommand('analytics-lens', 'analytics dashboard', {
1092
+ period: options.period,
1093
+ categories: options.categories,
1094
+ format: options.format,
1095
+ _: ['dashboard'],
1096
+ });
1097
+ if (options.json) {
1098
+ printJson(result);
1099
+ return;
1100
+ }
1101
+ console.log('');
1102
+ console.log(theme.success(' Analytics dashboard generated successfully!'));
1103
+ console.log(` ${theme.secondary('Dashboard:')} ${result.dashboard.name}`);
1104
+ console.log(` ${theme.secondary('Period:')} ${result.dashboard.period}`);
1105
+ console.log(` ${theme.secondary('Metrics:')} ${result.dashboard.metricCount}`);
1106
+ console.log(` ${theme.secondary('Output:')} ${result.filePath}`);
1107
+ console.log('');
1108
+ }
1109
+ catch (err) {
1110
+ const message = err instanceof Error ? err.message : 'Failed to generate analytics dashboard';
1111
+ if (options.json) {
1112
+ printJson({ status: 'error', error: message });
1113
+ }
1114
+ else {
1115
+ console.log('');
1116
+ console.log(theme.error(` ${message}`));
1117
+ console.log('');
1118
+ }
1119
+ process.exitCode = 1;
1120
+ }
1121
+ });
1122
+ analyticsCommand
1123
+ .command('report')
1124
+ .description('Generate analytics report')
1125
+ .option('--period <days>', 'Analysis period', 'last quarter')
1126
+ .option('--focus <area>', 'Report focus area')
1127
+ .option('--format <type>', 'Output format (json|markdown)', 'json')
1128
+ .option('--json', 'Output as JSON')
1129
+ .action(async (options) => {
1130
+ try {
1131
+ const moduleManager = getModuleManager();
1132
+ // Ensure analytics-lens module is installed
1133
+ if (!moduleManager.isInstalled('analytics-lens')) {
1134
+ console.log('');
1135
+ console.log(theme.warning(' Analytics Lens module not installed. Installing...'));
1136
+ await moduleManager.install('analytics-lens');
1137
+ }
1138
+ const result = await moduleManager.executeCommand('analytics-lens', 'analytics report', {
1139
+ period: options.period,
1140
+ focus: options.focus,
1141
+ format: options.format,
1142
+ _: ['report'],
1143
+ });
1144
+ if (options.json) {
1145
+ printJson(result);
1146
+ return;
1147
+ }
1148
+ console.log('');
1149
+ console.log(theme.success(' Analytics report generated successfully!'));
1150
+ console.log(` ${theme.secondary('Report:')} ${result.report.title}`);
1151
+ console.log(` ${theme.secondary('Period:')} ${result.report.period}`);
1152
+ console.log(` ${theme.secondary('Metrics:')} ${result.report.metricCount}`);
1153
+ console.log(` ${theme.secondary('Output:')} ${result.filePath}`);
1154
+ console.log('');
1155
+ }
1156
+ catch (err) {
1157
+ const message = err instanceof Error ? err.message : 'Failed to generate analytics report';
1158
+ if (options.json) {
1159
+ printJson({ status: 'error', error: message });
1160
+ }
1161
+ else {
1162
+ console.log('');
1163
+ console.log(theme.error(` ${message}`));
1164
+ console.log('');
1165
+ }
1166
+ process.exitCode = 1;
1167
+ }
1168
+ });
1169
+ analyticsCommand
1170
+ .description('Show analytics usage')
1171
+ .action(() => {
1172
+ console.log('');
1173
+ console.log(theme.title(' ANALYTICS LENS'));
1174
+ console.log(theme.secondary(' Connect to analytics platforms and surface actionable insights'));
1175
+ console.log('');
1176
+ console.log(` ${theme.accent('phantom analytics dashboard')}`);
1177
+ console.log(` ${theme.accent('phantom analytics report --period "last quarter"')}`);
1178
+ console.log(` ${theme.accent('phantom analytics dashboard --categories "user-engagement,revenue"')}`);
1179
+ console.log('');
1180
+ });
1181
+ docsCommand
1182
+ .command('generate')
1183
+ .description('Generate deterministic documentation artifacts')
1184
+ .option('--out <path>', 'Output directory path')
1185
+ .option('--json', 'Output as JSON')
1186
+ .action((options) => {
1187
+ try {
1188
+ const files = generateRealDocumentation(process.cwd(), options.out);
1189
+ if (options.json) {
1190
+ printJson({ files });
1191
+ return;
1192
+ }
1193
+ console.log('');
1194
+ console.log(theme.success(' Documentation generated:'));
1195
+ for (const file of files) {
1196
+ console.log(` ${theme.check} ${file}`);
1197
+ }
1198
+ console.log('');
1199
+ }
1200
+ catch (err) {
1201
+ const message = err instanceof Error ? err.message : 'Documentation generation failed';
1202
+ if (options.json) {
1203
+ printJson({ status: 'error', error: message });
1204
+ }
1205
+ else {
1206
+ console.log('');
1207
+ console.log(theme.error(` ${message}`));
1208
+ console.log('');
1209
+ }
1210
+ process.exitCode = 1;
1211
+ }
1212
+ });
1213
+ program
1214
+ .command('frameworks [action] [framework]')
1215
+ .description('List built-in PM frameworks')
1216
+ .option('--json', 'Output as JSON')
1217
+ .action((action, framework, options) => {
1218
+ if (!action || action === 'list') {
1219
+ if (options.json) {
1220
+ printJson({ frameworks: FRAMEWORKS });
1221
+ return;
1222
+ }
1223
+ 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
+ }
1229
+ console.log('');
1230
+ return;
1231
+ }
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
+ };
1238
+ if (options.json) {
1239
+ printJson(payload);
1240
+ }
1241
+ else {
1242
+ console.log('');
1243
+ console.log(theme.warning(` ${payload.message}`));
1244
+ console.log('');
1245
+ }
1246
+ 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
+ }
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
+ });
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')
1289
+ .option('--json', 'Output as JSON')
1290
+ .action(async (options) => {
1291
+ try {
1292
+ 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
+ });
1312
+ return;
1313
+ }
1314
+ // Interactive output
1315
+ await PhantomDiscovery.autoRegisterAll();
1316
+ }
1317
+ catch (error) {
1318
+ console.error(theme.error(' Failed to register agents:'), error);
1319
+ process.exitCode = 1;
1320
+ }
1321
+ });
1322
+ agentsCommand
1323
+ .command('health')
1324
+ .description('Check PHANTOM and agent connection health')
1325
+ .option('--json', 'Output as JSON')
1326
+ .action(async (options) => {
1327
+ try {
1328
+ 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);
1360
+ return;
1361
+ }
1362
+ // Interactive health check
1363
+ await PhantomDiscovery.healthCheck();
1364
+ }
1365
+ catch (error) {
1366
+ console.error(theme.error(' Health check failed:'), error);
1367
+ process.exitCode = 1;
1368
+ }
1369
+ });
1370
+ agentsCommand
1371
+ .command('scan')
1372
+ .description('Scan system for installed AI agents and LLMs')
1373
+ .option('--register', 'Automatically register detected agents')
1374
+ .option('--json', 'Output as JSON')
1375
+ .action(async (options) => {
1376
+ 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 });
1396
+ return;
1397
+ }
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
+ }
1423
+ }
1424
+ catch (err) {
1425
+ const message = err instanceof Error ? err.message : 'Agent scan failed';
1426
+ if (options.json) {
1427
+ printJson({ status: 'error', error: message });
1428
+ }
1429
+ else {
1430
+ console.log('');
1431
+ console.log(theme.error(` ${message}`));
1432
+ console.log('');
1433
+ }
1434
+ process.exitCode = 1;
1435
+ }
1436
+ });
1437
+ agentsCommand
1438
+ .command('list')
1439
+ .description('List registered agents and their integration status')
1440
+ .option('--json', 'Output as JSON')
1441
+ .action(async (options) => {
1442
+ try {
1443
+ const { AgentRegistry } = await import('@phantom/core');
1444
+ const registry = new AgentRegistry();
1445
+ const agents = registry.getAllAgents();
1446
+ if (options.json) {
1447
+ printJson({ agents });
1448
+ return;
1449
+ }
1450
+ console.log('');
1451
+ console.log(theme.title(' REGISTERED AGENTS'));
1452
+ 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'));
1456
+ console.log('');
1457
+ return;
1458
+ }
1459
+ for (const agent of agents) {
1460
+ const statusIcon = {
1461
+ 'connected': '🟢',
1462
+ 'running': '🟢',
1463
+ 'available': '🔵',
1464
+ 'installed': '🔵',
1465
+ 'offline': '🔴',
1466
+ 'unknown': '⚪'
1467
+ }[agent.status] || '⚪';
1468
+ const integrationLevel = agent.phantomIntegration.level;
1469
+ const levelColor = integrationLevel === 'full' ? theme.success :
1470
+ integrationLevel === 'enhanced' ? theme.warning :
1471
+ theme.dim;
1472
+ console.log(` ${statusIcon} ${theme.accent(agent.signature.name)}`);
1473
+ console.log(` Integration: ${levelColor(integrationLevel)}`);
1474
+ console.log(` Features: ${agent.phantomIntegration.featuresEnabled.join(', ') || 'None'}`);
1475
+ console.log(` Reliability: ${agent.performance.reliability}%`);
1476
+ console.log(` Last seen: ${new Date(agent.lastDetection).toLocaleString()}`);
1477
+ console.log('');
1478
+ }
1479
+ }
1480
+ catch (err) {
1481
+ const message = err instanceof Error ? err.message : 'Failed to list agents';
1482
+ if (options.json) {
1483
+ printJson({ status: 'error', error: message });
1484
+ }
1485
+ else {
1486
+ console.log('');
1487
+ console.log(theme.error(` ${message}`));
1488
+ console.log('');
1489
+ }
1490
+ process.exitCode = 1;
1491
+ }
1492
+ });
1493
+ agentsCommand
1494
+ .command('integrate <agentId>')
1495
+ .description('Enable Phantom integration for an agent')
1496
+ .option('--level <level>', 'Integration level: integrated, enhanced, full', 'enhanced')
1497
+ .option('--json', 'Output as JSON')
1498
+ .action(async (agentId, options) => {
1499
+ try {
1500
+ const { AgentRegistry } = await import('@phantom/core');
1501
+ const registry = new AgentRegistry();
1502
+ const validLevels = ['integrated', 'enhanced', 'full'];
1503
+ if (!validLevels.includes(options.level)) {
1504
+ throw new Error(`Invalid integration level. Choose from: ${validLevels.join(', ')}`);
1505
+ }
1506
+ const success = registry.enableIntegration(agentId, options.level);
1507
+ if (!success) {
1508
+ throw new Error(`Agent not found: ${agentId}`);
1509
+ }
1510
+ if (options.json) {
1511
+ printJson({ status: 'ok', agentId, level: options.level });
1512
+ return;
1513
+ }
1514
+ console.log('');
1515
+ console.log(theme.success(` Integration enabled for ${agentId}`));
1516
+ console.log(` Level: ${options.level}`);
1517
+ console.log(theme.dim(' Run: phantom agents list to see updated status'));
1518
+ console.log('');
1519
+ }
1520
+ catch (err) {
1521
+ const message = err instanceof Error ? err.message : 'Integration failed';
1522
+ if (options.json) {
1523
+ printJson({ status: 'error', error: message });
1524
+ }
1525
+ else {
1526
+ console.log('');
1527
+ console.log(theme.error(` ${message}`));
1528
+ console.log('');
1529
+ }
1530
+ process.exitCode = 1;
1531
+ }
1532
+ });
1533
+ agentsCommand
1534
+ .command('network')
1535
+ .description('Show agent network topology and connections')
1536
+ .option('--json', 'Output as JSON')
1537
+ .action(async (options) => {
1538
+ try {
1539
+ const { AgentRegistry } = await import('@phantom/core');
1540
+ const registry = new AgentRegistry();
1541
+ const topology = registry.getNetworkTopology();
1542
+ if (options.json) {
1543
+ printJson(topology);
1544
+ return;
1545
+ }
1546
+ console.log('');
1547
+ console.log(theme.title(' AGENT NETWORK TOPOLOGY'));
1548
+ console.log('');
1549
+ console.log(theme.secondary(`Agents: ${topology.agents.length}`));
1550
+ console.log(theme.secondary(`Connections: ${topology.connections.length}`));
1551
+ console.log(theme.secondary(`Clusters: ${topology.clusters.length}`));
1552
+ console.log('');
1553
+ if (topology.clusters.length > 0) {
1554
+ console.log(theme.title(' CLUSTERS'));
1555
+ for (const cluster of topology.clusters) {
1556
+ console.log(` ${theme.accent(cluster.name)}: ${cluster.agents.join(', ')}`);
1557
+ }
1558
+ console.log('');
1559
+ }
1560
+ if (topology.connections.length > 0) {
1561
+ console.log(theme.title(' CONNECTIONS'));
1562
+ for (const conn of topology.connections.slice(0, 10)) { // Show top 10
1563
+ const strengthBar = '█'.repeat(Math.floor(conn.strength / 20)) + '░'.repeat(5 - Math.floor(conn.strength / 20));
1564
+ console.log(` ${conn.from} → ${conn.to} [${strengthBar}] ${conn.strength}%`);
1565
+ }
1566
+ if (topology.connections.length > 10) {
1567
+ console.log(theme.dim(` ... and ${topology.connections.length - 10} more connections`));
1568
+ }
1569
+ }
1570
+ console.log('');
1571
+ }
1572
+ catch (err) {
1573
+ const message = err instanceof Error ? err.message : 'Network analysis failed';
1574
+ if (options.json) {
1575
+ printJson({ status: 'error', error: message });
1576
+ }
1577
+ else {
1578
+ console.log('');
1579
+ console.log(theme.error(` ${message}`));
1580
+ console.log('');
1581
+ }
1582
+ process.exitCode = 1;
1583
+ }
1584
+ });
1585
+ agentsCommand
1586
+ .description('Show Agent Matrix usage and capabilities')
1587
+ .action(() => {
1588
+ console.log('');
1589
+ console.log(theme.title(' PHANTOM AGENT MATRIX'));
1590
+ console.log(theme.secondary(' Connect and coordinate all your AI agents'));
1591
+ console.log('');
1592
+ console.log(` ${theme.accent('phantom agents scan')} # Detect installed AI agents`);
1593
+ console.log(` ${theme.accent('phantom agents list')} # Show registered agents`);
1594
+ console.log(` ${theme.accent('phantom agents integrate <id>')} # Enable integration`);
1595
+ console.log(` ${theme.accent('phantom agents network')} # View network topology`);
1596
+ console.log('');
1597
+ console.log(theme.dim(' Supported agents: Claude Code, Cursor, Codex, Gemini, ChatGPT, VS Code, Zed'));
1598
+ console.log('');
1599
+ });
1600
+ program
1601
+ .command('boot')
1602
+ .description('Run onboarding boot sequence')
1603
+ .action(async () => {
1604
+ await runBootSequence();
1605
+ await showFirstRunSetup();
1606
+ });
1607
+ program
1608
+ .command('tools')
1609
+ .description('Tool palette (real-mode gate)')
1610
+ .action(() => {
1611
+ failNotImplemented('tools');
1612
+ });
1613
+ function dirnameSafe(pathValue) {
1614
+ const idx = Math.max(pathValue.lastIndexOf('/'), pathValue.lastIndexOf('\\'));
1615
+ if (idx <= 0)
1616
+ return process.cwd();
1617
+ return pathValue.slice(0, idx);
1618
+ }
1619
+ const argv = [...process.argv];
1620
+ if (argv[2] === 'integrate' &&
1621
+ typeof argv[3] === 'string' &&
1622
+ !argv[3].startsWith('-') &&
1623
+ !['scan', 'doctor', 'connect'].includes(argv[3])) {
1624
+ argv.splice(3, 0, 'connect');
1625
+ }
1626
+ program.parse(argv);
1627
+ //# sourceMappingURL=index.js.map