@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/README.md +52 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +173 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/stories.d.ts +3 -0
- package/dist/commands/stories.d.ts.map +1 -0
- package/dist/commands/stories.js +119 -0
- package/dist/commands/stories.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1627 -0
- package/dist/index.js.map +1 -0
- package/package.json +70 -0
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
|