@targlobal/mission-control 1.2.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,1703 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const commander_1 = require("commander");
41
+ const chalk_1 = __importDefault(require("chalk"));
42
+ const ora_1 = __importDefault(require("ora"));
43
+ const cli_table3_1 = __importDefault(require("cli-table3"));
44
+ const inquirer_1 = __importDefault(require("inquirer"));
45
+ const config_1 = require("./config");
46
+ const api_1 = require("./api");
47
+ const child_process_1 = require("child_process");
48
+ const VERSION = '1.2.0';
49
+ const program = new commander_1.Command();
50
+ // Set terminal title
51
+ const setTitle = (context) => {
52
+ process.stdout.write(`\x1b]0;MC | ${context}\x07`);
53
+ };
54
+ // ASCII Art Logo
55
+ const logo = `
56
+ ${chalk_1.default.bold.white('███╗ ███╗ ██╗ ███████╗ ███████╗ ██╗ ██████╗ ███╗ ██╗')}
57
+ ${chalk_1.default.bold.white('████╗ ████║ ██║ ██╔════╝ ██╔════╝ ██║ ██╔═══██╗ ████╗ ██║')}
58
+ ${chalk_1.default.bold.white('██╔████╔██║ ██║ ███████╗ ███████╗ ██║ ██║ ██║ ██╔██╗ ██║')}
59
+ ${chalk_1.default.bold.white('██║╚██╔╝██║ ██║ ╚════██║ ╚════██║ ██║ ██║ ██║ ██║╚██╗██║')}
60
+ ${chalk_1.default.bold.white('██║ ╚═╝ ██║ ██║ ███████║ ███████║ ██║ ╚██████╔╝ ██║ ╚████║')}
61
+ ${chalk_1.default.bold.white('╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝')}
62
+
63
+ ${chalk_1.default.yellow('>>>')} ${chalk_1.default.bold.yellow('CONTROL')} ${chalk_1.default.dim('TAR Global Management')}
64
+ `;
65
+ const miniLogo = chalk_1.default.cyan('>>>') + chalk_1.default.bold.white(' Mission Control') + chalk_1.default.dim(' | TAR Global');
66
+ // Compact mode detection
67
+ const isCompact = () => {
68
+ const config = (0, config_1.getConfig)();
69
+ if (config.compact === 'on')
70
+ return true;
71
+ if (config.compact === 'off')
72
+ return false;
73
+ // Auto-detect based on terminal width
74
+ const width = process.stdout.columns || 80;
75
+ return width < 60;
76
+ };
77
+ const getTermWidth = () => process.stdout.columns || 80;
78
+ // Status bar showing user info
79
+ const showStatusBar = () => {
80
+ const user = (0, config_1.getUser)();
81
+ if (user) {
82
+ console.log(chalk_1.default.dim('─'.repeat(50)));
83
+ console.log(chalk_1.default.bold.white(` ${user.name}`) + chalk_1.default.dim(` | ${user.email}`));
84
+ console.log('');
85
+ }
86
+ };
87
+ // Fun completion messages (ASCII-safe)
88
+ const celebrations = [
89
+ chalk_1.default.green('*** Task completed! You\'re on fire! ***'),
90
+ chalk_1.default.green('*** Done! Another one bites the dust! ***'),
91
+ chalk_1.default.green('*** Shipped! To infinity and beyond! ***'),
92
+ chalk_1.default.green('*** Crushed it! Keep that momentum! ***'),
93
+ chalk_1.default.green('*** Victory! You\'re unstoppable! ***'),
94
+ chalk_1.default.green('*** Stellar work! Task obliterated! ***'),
95
+ chalk_1.default.green('*** Boom! Task destroyed! ***'),
96
+ chalk_1.default.green('*** Bullseye! Nailed it! ***'),
97
+ ];
98
+ const getRandomCelebration = () => celebrations[Math.floor(Math.random() * celebrations.length)];
99
+ // Priority colors and icons (ASCII-safe for terminal compatibility)
100
+ const priorityStyle = {
101
+ critical: { icon: chalk_1.default.red('●'), color: chalk_1.default.red },
102
+ high: { icon: chalk_1.default.yellow('●'), color: chalk_1.default.yellow },
103
+ medium: { icon: chalk_1.default.blue('●'), color: chalk_1.default.blue },
104
+ low: { icon: chalk_1.default.green('●'), color: chalk_1.default.green },
105
+ };
106
+ // Type icons (ASCII-safe)
107
+ const typeIcons = {
108
+ bug: chalk_1.default.red('[BUG]'),
109
+ feature: chalk_1.default.green('[FTR]'),
110
+ improvement: chalk_1.default.cyan('[IMP]'),
111
+ task: chalk_1.default.white('[TSK]'),
112
+ escalation: chalk_1.default.magenta('[ESC]'),
113
+ };
114
+ // Helper to check auth
115
+ const requireAuth = () => {
116
+ if (!(0, config_1.isAuthenticated)()) {
117
+ console.log(chalk_1.default.red('\n[!] Not authenticated. Run `mc login` first.\n'));
118
+ process.exit(1);
119
+ }
120
+ };
121
+ // Helper to parse task number (supports MC-1001 or just 1001)
122
+ const parseTaskNumber = (input) => {
123
+ return input.toUpperCase().replace('MC-', '');
124
+ };
125
+ // Helper to format date
126
+ const formatDate = (dateStr) => {
127
+ const date = new Date(dateStr);
128
+ const now = new Date();
129
+ const diffMs = now.getTime() - date.getTime();
130
+ const diffMins = Math.floor(diffMs / 60000);
131
+ const diffHours = Math.floor(diffMs / 3600000);
132
+ const diffDays = Math.floor(diffMs / 86400000);
133
+ if (diffMins < 1)
134
+ return 'just now';
135
+ if (diffMins < 60)
136
+ return `${diffMins}m ago`;
137
+ if (diffHours < 24)
138
+ return `${diffHours}h ago`;
139
+ if (diffDays < 7)
140
+ return `${diffDays}d ago`;
141
+ return date.toLocaleDateString();
142
+ };
143
+ // Fetch and store user info
144
+ const fetchUserInfo = async () => {
145
+ try {
146
+ const response = await api_1.api.getCurrentUser();
147
+ if (response.user) {
148
+ (0, config_1.setUser)({
149
+ name: response.user.display_name,
150
+ email: response.user.email,
151
+ });
152
+ }
153
+ }
154
+ catch (e) {
155
+ // Silently fail - user info is optional
156
+ }
157
+ };
158
+ program
159
+ .name('mc')
160
+ .description('Mission Control CLI - TAR Global Task Management')
161
+ .version(VERSION)
162
+ .addHelpText('before', logo);
163
+ // ==================== INTERACTIVE SHELL ====================
164
+ program
165
+ .command('shell')
166
+ .alias('i')
167
+ .description('Start interactive dashboard mode')
168
+ .action(async () => {
169
+ requireAuth();
170
+ await runInteractiveShell();
171
+ });
172
+ // Command functions for interactive mode
173
+ const listTasksCmd = async (options) => {
174
+ const spinner = (0, ora_1.default)('Loading tasks...').start();
175
+ try {
176
+ const data = options.all ? await api_1.api.listTasks({}) : await api_1.api.getMyTasks();
177
+ const tasks = data.tasks || [];
178
+ spinner.stop();
179
+ if (tasks.length === 0) {
180
+ console.log(chalk_1.default.dim('\n No tasks found\n'));
181
+ return;
182
+ }
183
+ const compact = isCompact();
184
+ const table = new cli_table3_1.default({
185
+ head: compact
186
+ ? [chalk_1.default.cyan('ID'), chalk_1.default.cyan('Title'), chalk_1.default.cyan('Pri')]
187
+ : [chalk_1.default.cyan('ID'), chalk_1.default.cyan('Title'), chalk_1.default.cyan('Priority'), chalk_1.default.cyan('Status'), chalk_1.default.cyan('Type')],
188
+ style: { head: [], border: [] },
189
+ colWidths: compact ? [8, 24, 6] : [10, 40, 12, 15, 8],
190
+ });
191
+ tasks.forEach((task) => {
192
+ const p = priorityStyle[task.priority] || priorityStyle.medium;
193
+ const titleLen = compact ? 21 : 37;
194
+ const title = task.title.length > titleLen ? task.title.substring(0, titleLen) + '...' : task.title;
195
+ if (compact) {
196
+ table.push([
197
+ chalk_1.default.dim(task.display_id.replace('MC-', '')),
198
+ title,
199
+ p.icon,
200
+ ]);
201
+ }
202
+ else {
203
+ table.push([
204
+ chalk_1.default.white(task.display_id),
205
+ title,
206
+ p.icon + ' ' + p.color(task.priority),
207
+ task.column_name,
208
+ typeIcons[task.task_type] || chalk_1.default.white('[TSK]'),
209
+ ]);
210
+ }
211
+ });
212
+ console.log('\n' + table.toString() + '\n');
213
+ console.log(chalk_1.default.dim(` ${tasks.length} task(s) found\n`));
214
+ }
215
+ catch (error) {
216
+ spinner.fail(chalk_1.default.red('Failed to load tasks'));
217
+ }
218
+ };
219
+ const showTaskCmd = async (taskId) => {
220
+ const spinner = (0, ora_1.default)('Loading task...').start();
221
+ const compact = isCompact();
222
+ try {
223
+ const task = await api_1.api.getTask(parseTaskNumber(taskId));
224
+ spinner.stop();
225
+ const p = priorityStyle[task.priority] || priorityStyle.medium;
226
+ const typeIcon = typeIcons[task.task_type] || chalk_1.default.white('[TSK]');
227
+ if (compact) {
228
+ // Compact task view
229
+ console.log('');
230
+ console.log(chalk_1.default.bold.white(`${task.display_id}: ${task.title.substring(0, 28)}`));
231
+ console.log(chalk_1.default.dim('─'.repeat(30)));
232
+ console.log(`${typeIcon} ${p.icon} ${p.color(task.priority)} ${chalk_1.default.dim('|')} ${task.column_name}`);
233
+ console.log(chalk_1.default.dim(`Board: ${task.board_name}`));
234
+ console.log(chalk_1.default.dim(`Created: ${formatDate(task.created_at)}`));
235
+ if (task.assignees.length > 0) {
236
+ const names = task.assignees.map((a) => a.display_name.split(' ')[0]).join(', ');
237
+ console.log(chalk_1.default.dim(`Assigned: ${names.substring(0, 25)}`));
238
+ }
239
+ if (task.is_completed) {
240
+ console.log(chalk_1.default.green(`✓ Done ${formatDate(task.completed_at)}`));
241
+ }
242
+ if (task.description) {
243
+ console.log(chalk_1.default.dim('\n' + task.description.substring(0, 100)));
244
+ if (task.description.length > 100)
245
+ console.log(chalk_1.default.dim('...'));
246
+ }
247
+ console.log('');
248
+ }
249
+ else {
250
+ console.log('\n' + chalk_1.default.bold.white('╭─────────────────────────────────────────────────────╮'));
251
+ console.log(chalk_1.default.bold.white(`│ ${task.display_id}: ${task.title.substring(0, 43).padEnd(43)} │`));
252
+ console.log(chalk_1.default.bold.white('├─────────────────────────────────────────────────────┤'));
253
+ console.log(`│ Type: ${typeIcon} ${task.task_type.padEnd(12)} Priority: ${p.icon} ${p.color(task.priority.padEnd(10))} │`);
254
+ console.log(`│ Board: ${task.board_name.padEnd(12)} Column: ${task.column_name.padEnd(15)} │`);
255
+ console.log(`│ Created: ${formatDate(task.created_at).padEnd(10)} by ${(task.created_by_name || 'Unknown').padEnd(20)} │`);
256
+ if (task.assignees.length > 0) {
257
+ const assigneeNames = task.assignees.map((a) => a.display_name).join(', ');
258
+ console.log(`│ Assignees: ${assigneeNames.substring(0, 40).padEnd(40)} │`);
259
+ }
260
+ if (task.is_completed) {
261
+ console.log(`│ ${chalk_1.default.green('[DONE]')} ${formatDate(task.completed_at).padEnd(41)} │`);
262
+ }
263
+ console.log(chalk_1.default.bold.white('╰─────────────────────────────────────────────────────╯'));
264
+ if (task.description) {
265
+ console.log(chalk_1.default.dim('\nDescription:'));
266
+ console.log(task.description.substring(0, 200));
267
+ if (task.description.length > 200)
268
+ console.log(chalk_1.default.dim('...'));
269
+ }
270
+ console.log('');
271
+ }
272
+ }
273
+ catch (error) {
274
+ spinner.fail(chalk_1.default.red('Failed to load task'));
275
+ }
276
+ };
277
+ const createTaskInteractive = async () => {
278
+ const boards = await api_1.api.listBoards();
279
+ const answers = await inquirer_1.default.prompt([
280
+ { type: 'input', name: 'title', message: 'Task title:' },
281
+ { type: 'input', name: 'description', message: 'Description (optional):' },
282
+ {
283
+ type: 'list',
284
+ name: 'board',
285
+ message: 'Board:',
286
+ choices: boards.boards.map((b) => ({ name: b.name, value: b.id })),
287
+ },
288
+ {
289
+ type: 'list',
290
+ name: 'priority',
291
+ message: 'Priority:',
292
+ choices: ['low', 'medium', 'high', 'critical'],
293
+ default: 'medium',
294
+ },
295
+ {
296
+ type: 'list',
297
+ name: 'type',
298
+ message: 'Type:',
299
+ choices: ['task', 'bug', 'feature', 'improvement'],
300
+ default: 'task',
301
+ },
302
+ ]);
303
+ const spinner = (0, ora_1.default)('Creating task...').start();
304
+ try {
305
+ const task = await api_1.api.createTask({
306
+ title: answers.title,
307
+ description: answers.description || undefined,
308
+ board: answers.board,
309
+ priority: answers.priority,
310
+ task_type: answers.type,
311
+ });
312
+ spinner.succeed(chalk_1.default.green(`Task created: ${task.display_id}`));
313
+ console.log(chalk_1.default.dim(` ${task.title}\n`));
314
+ }
315
+ catch (error) {
316
+ spinner.fail(chalk_1.default.red('Failed to create task'));
317
+ }
318
+ };
319
+ const startTaskCmd = async (taskId) => {
320
+ const spinner = (0, ora_1.default)('Starting task...').start();
321
+ try {
322
+ const task = await api_1.api.getTask(parseTaskNumber(taskId));
323
+ const boardData = await api_1.api.getBoard(task.board_name.toLowerCase().replace(' ', '-'));
324
+ const inProgressCol = boardData.columns.find((c) => c.name.toLowerCase().includes('progress'));
325
+ if (!inProgressCol) {
326
+ spinner.fail(chalk_1.default.red('Could not find In Progress column'));
327
+ return;
328
+ }
329
+ await api_1.api.moveTask(parseTaskNumber(taskId), inProgressCol.id);
330
+ spinner.succeed(chalk_1.default.green(`${task.display_id} moved to In Progress`));
331
+ }
332
+ catch (error) {
333
+ spinner.fail(chalk_1.default.red('Failed to start task'));
334
+ }
335
+ };
336
+ const completeTaskCmd = async (taskId) => {
337
+ const spinner = (0, ora_1.default)('Completing task...').start();
338
+ try {
339
+ const result = await api_1.api.completeTask(parseTaskNumber(taskId));
340
+ spinner.stop();
341
+ console.log('\n' + getRandomCelebration());
342
+ console.log(chalk_1.default.dim(` ${result.task.display_id}: ${result.task.title}`));
343
+ console.log(chalk_1.default.green('\n ╭────────────────────────────────╮'));
344
+ console.log(chalk_1.default.green(' │') + chalk_1.default.bold.yellow(' [*] TASK COMPLETED! [*] ') + chalk_1.default.green('│'));
345
+ console.log(chalk_1.default.green(' ╰────────────────────────────────╯\n'));
346
+ }
347
+ catch (error) {
348
+ spinner.fail(chalk_1.default.red('Failed to complete task'));
349
+ }
350
+ };
351
+ const listBoardsCmd = async () => {
352
+ const spinner = (0, ora_1.default)('Loading boards...').start();
353
+ const compact = isCompact();
354
+ try {
355
+ const data = await api_1.api.listBoards();
356
+ spinner.stop();
357
+ if (compact) {
358
+ console.log(chalk_1.default.cyan('\n Boards:'));
359
+ data.boards.forEach((board) => {
360
+ console.log(` ${chalk_1.default.white(board.slug.padEnd(10))} ${chalk_1.default.dim(board.task_count + ' tasks')}`);
361
+ });
362
+ console.log('');
363
+ }
364
+ else {
365
+ const table = new cli_table3_1.default({
366
+ head: [chalk_1.default.cyan('Slug'), chalk_1.default.cyan('Name'), chalk_1.default.cyan('Team'), chalk_1.default.cyan('Tasks')],
367
+ style: { head: [], border: [] },
368
+ });
369
+ data.boards.forEach((board) => {
370
+ table.push([board.slug, board.name, board.team, board.task_count.toString()]);
371
+ });
372
+ console.log('\n' + table.toString() + '\n');
373
+ }
374
+ }
375
+ catch (error) {
376
+ spinner.fail(chalk_1.default.red('Failed to load boards'));
377
+ }
378
+ };
379
+ const showStatsCmd = async () => {
380
+ const spinner = (0, ora_1.default)('Loading stats...').start();
381
+ const compact = isCompact();
382
+ try {
383
+ const stats = await api_1.api.getStats();
384
+ spinner.stop();
385
+ if (compact) {
386
+ console.log(chalk_1.default.cyan('\n YOUR STATS'));
387
+ console.log(chalk_1.default.dim(' ──────────────────'));
388
+ console.log(` Tasks: ${chalk_1.default.bold.white(stats.my_tasks)}`);
389
+ console.log(` Done: ${chalk_1.default.bold.green(stats.my_completed)}`);
390
+ console.log(` Overdue: ${chalk_1.default.bold.red(stats.overdue_tasks)}`);
391
+ console.log(` Critical: ${chalk_1.default.bold.yellow(stats.critical_count)}`);
392
+ console.log(` High: ${chalk_1.default.bold.yellow(stats.high_count)}`);
393
+ console.log('');
394
+ }
395
+ else {
396
+ console.log('\n' + miniLogo);
397
+ console.log(chalk_1.default.cyan('\n ╭──────────────────────────────╮'));
398
+ console.log(chalk_1.default.cyan(' │') + chalk_1.default.bold.white(' [=] YOUR STATS [=] ') + chalk_1.default.cyan('│'));
399
+ console.log(chalk_1.default.cyan(' ├──────────────────────────────┤'));
400
+ console.log(chalk_1.default.cyan(' │') + ` [T] My Tasks: ${chalk_1.default.bold.white(String(stats.my_tasks).padStart(6))} ` + chalk_1.default.cyan('│'));
401
+ console.log(chalk_1.default.cyan(' │') + ` [+] Completed: ${chalk_1.default.bold.green(String(stats.my_completed).padStart(6))} ` + chalk_1.default.cyan('│'));
402
+ console.log(chalk_1.default.cyan(' │') + ` [!] Overdue: ${chalk_1.default.bold.red(String(stats.overdue_tasks).padStart(6))} ` + chalk_1.default.cyan('│'));
403
+ console.log(chalk_1.default.cyan(' │') + ` ${chalk_1.default.red('●')} Critical: ${chalk_1.default.bold.yellow(String(stats.critical_count).padStart(6))} ` + chalk_1.default.cyan('│'));
404
+ console.log(chalk_1.default.cyan(' │') + ` ${chalk_1.default.yellow('●')} High: ${chalk_1.default.bold.yellow(String(stats.high_count).padStart(6))} ` + chalk_1.default.cyan('│'));
405
+ console.log(chalk_1.default.cyan(' ╰──────────────────────────────╯\n'));
406
+ }
407
+ }
408
+ catch (error) {
409
+ spinner.fail(chalk_1.default.red('Failed to load stats'));
410
+ }
411
+ };
412
+ const showUrgentCmd = async () => {
413
+ const spinner = (0, ora_1.default)('Loading urgent tasks...').start();
414
+ try {
415
+ const data = await api_1.api.listTasks({ priority: 'critical' });
416
+ const tasks = data.tasks || [];
417
+ spinner.stop();
418
+ if (tasks.length === 0) {
419
+ console.log(chalk_1.default.green('\n [OK] No critical tasks! All clear.\n'));
420
+ return;
421
+ }
422
+ console.log(chalk_1.default.red.bold(`\n [!!!] ${tasks.length} critical task(s) need attention:\n`));
423
+ tasks.forEach((task) => {
424
+ console.log(` ${chalk_1.default.red('●')} ${task.display_id}: ${task.title}`);
425
+ console.log(chalk_1.default.dim(` ${task.board_name} → ${task.column_name}`));
426
+ });
427
+ console.log('');
428
+ }
429
+ catch (error) {
430
+ spinner.fail(chalk_1.default.red('Failed to load tasks'));
431
+ }
432
+ };
433
+ const showWhoami = () => {
434
+ const config = (0, config_1.getConfig)();
435
+ const user = (0, config_1.getUser)();
436
+ const termWidth = getTermWidth();
437
+ console.log('\n' + chalk_1.default.bold(' Mission Control Config'));
438
+ console.log(chalk_1.default.dim(' ──────────────────────'));
439
+ if (user) {
440
+ console.log(` User: ${chalk_1.default.bold.white(user.name)}`);
441
+ console.log(` Email: ${user.email}`);
442
+ }
443
+ console.log(` API URL: ${config.apiUrl}`);
444
+ console.log(` Token: ${config.token ? chalk_1.default.green('●') + ' configured' : chalk_1.default.red('○') + ' not set'}`);
445
+ console.log(` Compact: ${chalk_1.default.cyan(config.compact)} ${chalk_1.default.dim(`(term: ${termWidth} cols)`)}`);
446
+ console.log(` Version: ${VERSION}`);
447
+ console.log('');
448
+ };
449
+ const showInteractiveHelp = () => {
450
+ const compact = isCompact();
451
+ if (compact) {
452
+ console.log(chalk_1.default.cyan('\n Commands:'));
453
+ console.log(chalk_1.default.dim(' ─────────────'));
454
+ console.log(' tasks/ls List tasks');
455
+ console.log(' show <id> Task details');
456
+ console.log(' new Create task');
457
+ console.log(' done <id> Complete');
458
+ console.log(' stats Statistics');
459
+ console.log(' payouts Payouts');
460
+ console.log(' config Settings');
461
+ console.log(' exit/q Quit');
462
+ console.log('');
463
+ }
464
+ else {
465
+ console.log(chalk_1.default.cyan('\n Available Commands:'));
466
+ console.log(chalk_1.default.dim(' ──────────────────────'));
467
+ console.log(' tasks, ls List your tasks');
468
+ console.log(' tasks -a List all tasks');
469
+ console.log(' show <id> Show task details');
470
+ console.log(' new Create new task (interactive)');
471
+ console.log(' start <id> Move task to In Progress');
472
+ console.log(' done <id> Complete a task');
473
+ console.log(' boards List boards');
474
+ console.log(' stats Show your statistics');
475
+ console.log(' urgent Show critical tasks');
476
+ console.log(chalk_1.default.yellow(' payouts Payout processing dashboard'));
477
+ console.log(' whoami Show current user/config');
478
+ console.log(' config View/set config (compact mode)');
479
+ console.log(' clear Clear screen');
480
+ console.log(' help, ? Show this help');
481
+ console.log(' exit, quit, q Exit shell');
482
+ console.log('');
483
+ }
484
+ };
485
+ // ==================== INTERACTIVE DASHBOARD SHELL ====================
486
+ const showDashboard = async () => {
487
+ try {
488
+ const stats = await api_1.api.getStats();
489
+ const user = (0, config_1.getUser)();
490
+ const now = new Date();
491
+ const greeting = now.getHours() < 12 ? 'Good morning' : now.getHours() < 18 ? 'Good afternoon' : 'Good evening';
492
+ const compact = isCompact();
493
+ console.clear();
494
+ if (compact) {
495
+ // Compact mobile dashboard
496
+ console.log(miniLogo);
497
+ console.log('');
498
+ const firstName = (user?.name || 'Agent').split(' ')[0];
499
+ console.log(chalk_1.default.dim(`${greeting}, `) + chalk_1.default.bold.yellow(firstName));
500
+ console.log('');
501
+ console.log(chalk_1.default.cyan('┌─────────────────────────────┐'));
502
+ console.log(chalk_1.default.cyan('│') + ` ${chalk_1.default.bgCyan.black('TASKS')} ${chalk_1.default.bold.white(String(stats.my_tasks).padStart(3))} ${chalk_1.default.bgRed.white('CRIT')} ${chalk_1.default.bold.red(String(stats.critical_count).padStart(2))} ${chalk_1.default.bgYellow.black('OVR')} ${chalk_1.default.bold.yellow(String(stats.overdue_tasks).padStart(2))} ` + chalk_1.default.cyan('│'));
503
+ console.log(chalk_1.default.cyan('├─────────────────────────────┤'));
504
+ console.log(chalk_1.default.cyan('│') + ` ${chalk_1.default.cyan('[1]')}Tasks ${chalk_1.default.cyan('[2]')}New ${chalk_1.default.cyan('[3]')}Pay ${chalk_1.default.cyan('[4]')}Urg ` + chalk_1.default.cyan('│'));
505
+ console.log(chalk_1.default.cyan('└─────────────────────────────┘'));
506
+ console.log('');
507
+ // Show urgent count only in compact mode
508
+ if (stats.critical_count > 0 || stats.overdue_tasks > 0) {
509
+ console.log(chalk_1.default.red(`! ${stats.critical_count} critical task(s)`));
510
+ }
511
+ }
512
+ else {
513
+ // Full dashboard
514
+ const blinkDots = chalk_1.default.cyan('\x1b[5m●●●\x1b[0m'); // Blinking dots
515
+ console.log(logo);
516
+ console.log('');
517
+ console.log(chalk_1.default.cyan('╔══════════════════════════════════════════════════════════════════════╗'));
518
+ console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.bold.white(greeting)}, ${chalk_1.default.bold.yellow((user?.name || 'Agent').substring(0, 35))}`.padEnd(60) + ` ${blinkDots} ` + chalk_1.default.cyan('║'));
519
+ console.log(chalk_1.default.cyan('╠══════════════════════════════════════════════════════════════════════╣'));
520
+ console.log(chalk_1.default.cyan('║') + ' ' + chalk_1.default.cyan('║'));
521
+ console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.bgCyan.black(' MY TASKS ')} ${chalk_1.default.bgRed.white(' CRITICAL ')} ${chalk_1.default.bgYellow.black(' OVERDUE ')} ${chalk_1.default.bgGreen.black(' DONE ')} ` + chalk_1.default.cyan('║'));
522
+ console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.bold.white(String(stats.my_tasks).padStart(3))} ${chalk_1.default.bold.red(String(stats.critical_count).padStart(3))} ${chalk_1.default.bold.yellow(String(stats.overdue_tasks).padStart(3))} ${chalk_1.default.bold.green(String(stats.my_completed).padStart(3))} ` + chalk_1.default.cyan('║'));
523
+ console.log(chalk_1.default.cyan('║') + ' ' + chalk_1.default.cyan('║'));
524
+ console.log(chalk_1.default.cyan('╠══════════════════════════════════════════════════════════════════════╣'));
525
+ console.log(chalk_1.default.cyan('║') + chalk_1.default.dim(' Quick Actions: ') + chalk_1.default.cyan('║'));
526
+ console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.cyan('[1]')} My Tasks ${chalk_1.default.cyan('[2]')} New Task ${chalk_1.default.cyan('[3]')} Payouts ${chalk_1.default.cyan('[4]')} Urgent ` + chalk_1.default.cyan('║'));
527
+ console.log(chalk_1.default.cyan('║') + ' ' + chalk_1.default.cyan('║'));
528
+ console.log(chalk_1.default.cyan('╚══════════════════════════════════════════════════════════════════════╝'));
529
+ console.log('');
530
+ // Show recent urgent tasks if any
531
+ if (stats.critical_count > 0 || stats.overdue_tasks > 0) {
532
+ console.log(chalk_1.default.red.bold(' ⚠️ ATTENTION REQUIRED:'));
533
+ const urgentData = await api_1.api.listTasks({ priority: 'critical' });
534
+ const urgentTasks = (urgentData.tasks || []).slice(0, 3);
535
+ urgentTasks.forEach((t) => {
536
+ console.log(` ${chalk_1.default.red('●')} ${chalk_1.default.dim(t.display_id)} ${t.title.substring(0, 45)}`);
537
+ });
538
+ console.log('');
539
+ }
540
+ }
541
+ }
542
+ catch (e) {
543
+ // Silently fail - show basic prompt
544
+ }
545
+ };
546
+ const runInteractiveShell = async () => {
547
+ setTitle('Mission Control');
548
+ await showDashboard();
549
+ const runLoop = async () => {
550
+ const user = (0, config_1.getUser)();
551
+ const prompt = chalk_1.default.cyan('mc') + chalk_1.default.dim(` ${user?.name?.split(' ')[0] || ''}`) + chalk_1.default.cyan(' ❯ ');
552
+ const { command } = await inquirer_1.default.prompt([
553
+ {
554
+ type: 'input',
555
+ name: 'command',
556
+ message: prompt,
557
+ prefix: '',
558
+ },
559
+ ]);
560
+ const cmd = command.trim().toLowerCase();
561
+ const parts = command.trim().split(/\s+/);
562
+ const mainCmd = parts[0]?.toLowerCase();
563
+ const args = parts.slice(1);
564
+ // Exit commands
565
+ if (cmd === 'exit' || cmd === 'quit' || cmd === 'q') {
566
+ console.log(chalk_1.default.dim('\n 👋 See you later!\n'));
567
+ process.exit(0);
568
+ }
569
+ if (cmd === '') {
570
+ return runLoop();
571
+ }
572
+ try {
573
+ // Quick number shortcuts
574
+ if (cmd === '1') {
575
+ setTitle('My Tasks');
576
+ await listTasksCmd({});
577
+ }
578
+ else if (cmd === '2') {
579
+ setTitle('New Task');
580
+ await createTaskInteractive();
581
+ }
582
+ else if (cmd === '3') {
583
+ await runPayoutsShell();
584
+ await showDashboard();
585
+ }
586
+ else if (cmd === '4') {
587
+ setTitle('Urgent');
588
+ await showUrgentCmd();
589
+ }
590
+ else {
591
+ // Regular commands
592
+ switch (mainCmd) {
593
+ case 'dashboard':
594
+ case 'home':
595
+ case 'h':
596
+ await showDashboard();
597
+ break;
598
+ case 'tasks':
599
+ case 'ls':
600
+ setTitle('Tasks');
601
+ await listTasksCmd({ all: args.includes('-a') || args.includes('--all') });
602
+ break;
603
+ case 'show':
604
+ case 'view':
605
+ if (args[0]) {
606
+ setTitle(`Task ${args[0]}`);
607
+ await showTaskCmd(args[0]);
608
+ }
609
+ else {
610
+ console.log(chalk_1.default.red(' Usage: show <taskId>\n'));
611
+ }
612
+ break;
613
+ case 'new':
614
+ case 'create':
615
+ setTitle('New Task');
616
+ await createTaskInteractive();
617
+ break;
618
+ case 'start':
619
+ if (args[0]) {
620
+ await startTaskCmd(args[0]);
621
+ }
622
+ else {
623
+ console.log(chalk_1.default.red(' Usage: start <taskId>\n'));
624
+ }
625
+ break;
626
+ case 'done':
627
+ case 'complete':
628
+ if (args[0]) {
629
+ await completeTaskCmd(args[0]);
630
+ }
631
+ else {
632
+ console.log(chalk_1.default.red(' Usage: done <taskId>\n'));
633
+ }
634
+ break;
635
+ case 'boards':
636
+ setTitle('Boards');
637
+ await listBoardsCmd();
638
+ break;
639
+ case 'stats':
640
+ setTitle('Stats');
641
+ await showStatsCmd();
642
+ break;
643
+ case 'urgent':
644
+ setTitle('Urgent');
645
+ await showUrgentCmd();
646
+ break;
647
+ case 'payouts':
648
+ case 'payout':
649
+ case 'pay':
650
+ await runPayoutsShell();
651
+ await showDashboard();
652
+ break;
653
+ case 'whoami':
654
+ showWhoami();
655
+ break;
656
+ case 'help':
657
+ case '?':
658
+ showInteractiveHelp();
659
+ break;
660
+ case 'clear':
661
+ case 'cls':
662
+ await showDashboard();
663
+ break;
664
+ case 'refresh':
665
+ case 'r':
666
+ await showDashboard();
667
+ break;
668
+ case 'config':
669
+ if (args[0] === 'compact' && args[1]) {
670
+ if (['auto', 'on', 'off'].includes(args[1])) {
671
+ (0, config_1.setConfig)('compact', args[1]);
672
+ console.log(chalk_1.default.green(`\n ✓ Compact mode: ${args[1]}\n`));
673
+ await showDashboard();
674
+ }
675
+ else {
676
+ console.log(chalk_1.default.red('\n Use: config compact auto/on/off\n'));
677
+ }
678
+ }
679
+ else {
680
+ const cfg = (0, config_1.getConfig)();
681
+ console.log(chalk_1.default.cyan('\n Config:'));
682
+ console.log(` compact: ${chalk_1.default.bold(cfg.compact)} ${chalk_1.default.dim('(auto/on/off)')}`);
683
+ console.log(chalk_1.default.dim('\n Usage: config compact on\n'));
684
+ }
685
+ break;
686
+ default:
687
+ console.log(chalk_1.default.red(` Unknown command: ${mainCmd}`));
688
+ console.log(chalk_1.default.dim(' Type "help" for available commands\n'));
689
+ }
690
+ }
691
+ }
692
+ catch (e) {
693
+ console.log(chalk_1.default.red(` Error: ${e.message}\n`));
694
+ }
695
+ setTitle('Mission Control');
696
+ return runLoop();
697
+ };
698
+ await runLoop();
699
+ };
700
+ // ==================== PAYOUT FUNCTIONS ====================
701
+ const PLAN_COLORS = {
702
+ hermes: chalk_1.default.yellow,
703
+ alpha: chalk_1.default.cyan,
704
+ mematic: chalk_1.default.magenta,
705
+ validator_v2: chalk_1.default.blue,
706
+ booster: chalk_1.default.green,
707
+ dumpster: chalk_1.default.gray,
708
+ };
709
+ const PLAN_ICONS = {
710
+ hermes: '⚡',
711
+ alpha: '🔷',
712
+ mematic: '💎',
713
+ validator_v2: '🔐',
714
+ booster: '🚀',
715
+ dumpster: '🗑️',
716
+ };
717
+ const formatAmount = (amount, crypto) => {
718
+ const formatted = amount.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 4 });
719
+ return crypto ? `${formatted} ${crypto}` : `$${formatted}`;
720
+ };
721
+ const formatWallet = (address, length = 16) => {
722
+ if (address.length <= length)
723
+ return address;
724
+ return address.substring(0, 8) + '...' + address.substring(address.length - 6);
725
+ };
726
+ const showPayoutDashboard = async () => {
727
+ const spinner = (0, ora_1.default)('Loading payout dashboard...').start();
728
+ const compact = isCompact();
729
+ try {
730
+ // Fetch metrics for all plans
731
+ const metricsData = await api_1.api.getPayoutMetrics();
732
+ const metrics = metricsData.data;
733
+ // Fetch pending payouts
734
+ const payoutsData = await api_1.api.listPayouts({ status: 'pending', limit: 50 });
735
+ const payouts = payoutsData.data || [];
736
+ spinner.stop();
737
+ if (compact) {
738
+ // Compact mobile payout dashboard
739
+ console.log('\n' + chalk_1.default.yellow('>>> PAYOUTS'));
740
+ console.log('');
741
+ console.log(chalk_1.default.cyan('┌─────────────────────────────┐'));
742
+ console.log(chalk_1.default.cyan('│') + ` ${chalk_1.default.yellow('PEND')} ${String(metrics.pending_payouts).padStart(3)} ${chalk_1.default.green('DONE')} ${String(metrics.completed_payouts).padStart(4)} ${chalk_1.default.red('FAIL')} ${String(metrics.failed_payouts).padStart(2)} ` + chalk_1.default.cyan('│'));
743
+ console.log(chalk_1.default.cyan('├─────────────────────────────┤'));
744
+ console.log(chalk_1.default.cyan('│') + ` Pending: ${chalk_1.default.yellow('$' + metrics.pending_amount.toLocaleString())}`.padEnd(29) + chalk_1.default.cyan('│'));
745
+ console.log(chalk_1.default.cyan('│') + ` Paid: ${chalk_1.default.green('$' + metrics.paid_amount.toLocaleString())}`.padEnd(29) + chalk_1.default.cyan('│'));
746
+ console.log(chalk_1.default.cyan('└─────────────────────────────┘'));
747
+ if (payouts.length === 0) {
748
+ console.log(chalk_1.default.green('\n ✓ No pending payouts\n'));
749
+ return;
750
+ }
751
+ // Group payouts by plan
752
+ const byPlan = {};
753
+ payouts.forEach((p) => {
754
+ if (!byPlan[p.plan])
755
+ byPlan[p.plan] = [];
756
+ byPlan[p.plan].push(p);
757
+ });
758
+ console.log(chalk_1.default.dim('\nPENDING BY PLAN:'));
759
+ Object.entries(byPlan).forEach(([plan, planPayouts]) => {
760
+ const planColor = PLAN_COLORS[plan] || chalk_1.default.white;
761
+ const byCrypto = {};
762
+ planPayouts.forEach((p) => {
763
+ if (!byCrypto[p.crypto_type])
764
+ byCrypto[p.crypto_type] = 0;
765
+ byCrypto[p.crypto_type] += p.amount;
766
+ });
767
+ const cryptoTotals = Object.entries(byCrypto).map(([crypto, amt]) => `${amt.toFixed(2)} ${crypto}`).join(', ');
768
+ console.log(` ${planColor(plan.toUpperCase())} ${chalk_1.default.dim('|')} ${planPayouts.length} ${chalk_1.default.dim('|')} ${chalk_1.default.yellow(cryptoTotals)}`);
769
+ // Show first 2 payouts
770
+ planPayouts.slice(0, 2).forEach((p) => {
771
+ const email = p.user_email.length > 15 ? p.user_email.substring(0, 13) + '..' : p.user_email;
772
+ console.log(chalk_1.default.dim(` #${p.id} ${email} ${chalk_1.default.green(p.amount.toFixed(2))} ${p.crypto_type}`));
773
+ });
774
+ if (planPayouts.length > 2) {
775
+ console.log(chalk_1.default.dim(` ... +${planPayouts.length - 2} more`));
776
+ }
777
+ });
778
+ console.log(chalk_1.default.dim('\nCmds: list, approve, cancel, back\n'));
779
+ }
780
+ else {
781
+ // Full dashboard
782
+ console.log('\n' + chalk_1.default.cyan('╔════════════════════════════════════════════════════════════════╗'));
783
+ console.log(chalk_1.default.cyan('║') + chalk_1.default.bold.white(' 💰 PAYOUT CONTROL CENTER 💰 ') + chalk_1.default.cyan('║'));
784
+ console.log(chalk_1.default.cyan('╠════════════════════════════════════════════════════════════════╣'));
785
+ // Metrics Row
786
+ console.log(chalk_1.default.cyan('║') + ' ' + chalk_1.default.cyan('║'));
787
+ console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.bold.yellow('PENDING')} ${chalk_1.default.bold.green('COMPLETED')} ${chalk_1.default.bold.red('FAILED')} ${chalk_1.default.bold.white('TOTAL')} ` + chalk_1.default.cyan('║'));
788
+ console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.yellow(String(metrics.pending_payouts).padStart(4))} ${chalk_1.default.green(String(metrics.completed_payouts).padStart(5))} ${chalk_1.default.red(String(metrics.failed_payouts).padStart(3))} ${chalk_1.default.white(String(metrics.total_payouts).padStart(5))} ` + chalk_1.default.cyan('║'));
789
+ console.log(chalk_1.default.cyan('║') + ' ' + chalk_1.default.cyan('║'));
790
+ console.log(chalk_1.default.cyan('╠════════════════════════════════════════════════════════════════╣'));
791
+ // Amount Stats
792
+ console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.dim('Pending Amount:')} ${chalk_1.default.yellow('$' + metrics.pending_amount.toLocaleString())}`.padEnd(64) + chalk_1.default.cyan('║'));
793
+ console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.dim('Paid Amount:')} ${chalk_1.default.green('$' + metrics.paid_amount.toLocaleString())}`.padEnd(64) + chalk_1.default.cyan('║'));
794
+ console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.dim('Total Volume:')} ${chalk_1.default.white('$' + metrics.total_amount.toLocaleString())}`.padEnd(64) + chalk_1.default.cyan('║'));
795
+ console.log(chalk_1.default.cyan('╠════════════════════════════════════════════════════════════════╣'));
796
+ if (payouts.length === 0) {
797
+ console.log(chalk_1.default.cyan('║') + chalk_1.default.green(' ✓ No pending payouts. All clear! ') + chalk_1.default.cyan('║'));
798
+ console.log(chalk_1.default.cyan('╚════════════════════════════════════════════════════════════════╝\n'));
799
+ return;
800
+ }
801
+ // Group payouts by plan
802
+ const byPlan = {};
803
+ payouts.forEach((p) => {
804
+ if (!byPlan[p.plan])
805
+ byPlan[p.plan] = [];
806
+ byPlan[p.plan].push(p);
807
+ });
808
+ console.log(chalk_1.default.cyan('║') + chalk_1.default.bold.white(' PENDING PAYOUTS BY PLAN ') + chalk_1.default.cyan('║'));
809
+ console.log(chalk_1.default.cyan('╠════════════════════════════════════════════════════════════════╣'));
810
+ // Show payouts by plan
811
+ Object.entries(byPlan).forEach(([plan, planPayouts]) => {
812
+ const planColor = PLAN_COLORS[plan] || chalk_1.default.white;
813
+ const planIcon = PLAN_ICONS[plan] || '📋';
814
+ // Group amounts by crypto type
815
+ const byCrypto = {};
816
+ planPayouts.forEach((p) => {
817
+ if (!byCrypto[p.crypto_type])
818
+ byCrypto[p.crypto_type] = 0;
819
+ byCrypto[p.crypto_type] += p.amount;
820
+ });
821
+ const cryptoTotals = Object.entries(byCrypto).map(([crypto, amt]) => `${amt.toFixed(2)} ${crypto}`).join(', ');
822
+ console.log(chalk_1.default.cyan('║') + ` ${planIcon} ${planColor(plan.toUpperCase().padEnd(12))} ${chalk_1.default.dim('|')} ${chalk_1.default.white(planPayouts.length + ' payouts')} ${chalk_1.default.dim('|')} ${chalk_1.default.yellow(cryptoTotals)}`.padEnd(72) + chalk_1.default.cyan('║'));
823
+ // Show first 3 payouts for this plan
824
+ planPayouts.slice(0, 3).forEach((p) => {
825
+ const idStr = chalk_1.default.dim(`#${p.id}`);
826
+ const emailStr = p.user_email.length > 20 ? p.user_email.substring(0, 18) + '..' : p.user_email;
827
+ const amountStr = formatAmount(p.amount, p.crypto_type);
828
+ const walletStr = formatWallet(p.wallet_address);
829
+ console.log(chalk_1.default.cyan('║') + ` ${idStr} ${chalk_1.default.white(emailStr.padEnd(20))} ${chalk_1.default.green(amountStr.padStart(14))} ${chalk_1.default.dim(walletStr)}`.padEnd(72) + chalk_1.default.cyan('║'));
830
+ });
831
+ if (planPayouts.length > 3) {
832
+ console.log(chalk_1.default.cyan('║') + chalk_1.default.dim(` ... and ${planPayouts.length - 3} more`).padEnd(64) + chalk_1.default.cyan('║'));
833
+ }
834
+ console.log(chalk_1.default.cyan('║') + ' ' + chalk_1.default.cyan('║'));
835
+ });
836
+ console.log(chalk_1.default.cyan('╠════════════════════════════════════════════════════════════════╣'));
837
+ console.log(chalk_1.default.cyan('║') + chalk_1.default.dim(' Commands: list, approve <ids>, cancel <ids>, process, back ') + chalk_1.default.cyan('║'));
838
+ console.log(chalk_1.default.cyan('╚════════════════════════════════════════════════════════════════╝\n'));
839
+ }
840
+ }
841
+ catch (error) {
842
+ spinner.fail(chalk_1.default.red('Failed to load payout dashboard'));
843
+ if (error.response?.status === 403) {
844
+ console.log(chalk_1.default.red('\n ⛔ Access Denied: Only managers and executors can access payouts\n'));
845
+ }
846
+ else {
847
+ console.log(chalk_1.default.dim(` ${error.response?.data?.error || error.message}\n`));
848
+ }
849
+ }
850
+ };
851
+ const listPayoutsCmd = async (options) => {
852
+ const spinner = (0, ora_1.default)('Loading payouts...').start();
853
+ const compact = isCompact();
854
+ try {
855
+ const data = await api_1.api.listPayouts({
856
+ plan: options.plan,
857
+ status: options.status || 'pending',
858
+ page: options.page || 1,
859
+ limit: compact ? 10 : 20,
860
+ });
861
+ const payouts = data.data || [];
862
+ spinner.stop();
863
+ if (payouts.length === 0) {
864
+ console.log(chalk_1.default.dim('\n No payouts found\n'));
865
+ return;
866
+ }
867
+ if (compact) {
868
+ // Compact list view
869
+ console.log('');
870
+ payouts.forEach((p) => {
871
+ const planColor = PLAN_COLORS[p.plan] || chalk_1.default.white;
872
+ const statusIcon = p.payed ? chalk_1.default.green('✓') : p.triggered ? chalk_1.default.yellow('~') : chalk_1.default.red('●');
873
+ const email = p.user_email.length > 12 ? p.user_email.substring(0, 10) + '..' : p.user_email;
874
+ console.log(` ${statusIcon} ${chalk_1.default.dim('#' + p.id)} ${planColor(p.plan.substring(0, 6))} ${email} ${chalk_1.default.green(p.amount.toFixed(2))} ${p.crypto_type}`);
875
+ });
876
+ console.log(chalk_1.default.dim(`\n Pg ${data.pagination.page}/${data.pagination.pages} (${data.pagination.total})\n`));
877
+ }
878
+ else {
879
+ const table = new cli_table3_1.default({
880
+ head: [
881
+ chalk_1.default.cyan('ID'),
882
+ chalk_1.default.cyan('User'),
883
+ chalk_1.default.cyan('Plan'),
884
+ chalk_1.default.cyan('Amount'),
885
+ chalk_1.default.cyan('Crypto'),
886
+ chalk_1.default.cyan('Wallet'),
887
+ chalk_1.default.cyan('Status'),
888
+ ],
889
+ style: { head: [], border: [] },
890
+ colWidths: [8, 22, 12, 14, 10, 18, 10],
891
+ });
892
+ payouts.forEach((p) => {
893
+ const planColor = PLAN_COLORS[p.plan] || chalk_1.default.white;
894
+ const statusIcon = p.payed ? chalk_1.default.green('✓ Paid') : p.triggered ? chalk_1.default.yellow('⏳ Proc') : chalk_1.default.red('● Pend');
895
+ table.push([
896
+ chalk_1.default.dim(String(p.id)),
897
+ p.user_email.length > 20 ? p.user_email.substring(0, 18) + '..' : p.user_email,
898
+ planColor(p.plan),
899
+ chalk_1.default.green('$' + p.amount.toFixed(2)),
900
+ p.crypto_type,
901
+ formatWallet(p.wallet_address, 16),
902
+ statusIcon,
903
+ ]);
904
+ });
905
+ console.log('\n' + table.toString());
906
+ console.log(chalk_1.default.dim(`\n Page ${data.pagination.page}/${data.pagination.pages} (${data.pagination.total} total)\n`));
907
+ }
908
+ }
909
+ catch (error) {
910
+ spinner.fail(chalk_1.default.red('Failed to load payouts'));
911
+ console.log(chalk_1.default.dim(` ${error.response?.data?.error || error.message}\n`));
912
+ }
913
+ };
914
+ const approvePayoutsCmd = async (ids) => {
915
+ if (ids.length === 0) {
916
+ console.log(chalk_1.default.red('\n No payout IDs provided\n'));
917
+ return;
918
+ }
919
+ // Confirmation
920
+ const { confirm } = await inquirer_1.default.prompt([
921
+ {
922
+ type: 'confirm',
923
+ name: 'confirm',
924
+ message: chalk_1.default.yellow(`⚠️ Approve and send ${ids.length} payout(s) via TarPay?`),
925
+ default: false,
926
+ },
927
+ ]);
928
+ if (!confirm) {
929
+ console.log(chalk_1.default.dim('\n Cancelled\n'));
930
+ return;
931
+ }
932
+ const spinner = (0, ora_1.default)(`Processing ${ids.length} payouts...`).start();
933
+ try {
934
+ const result = await api_1.api.batchApprovePayouts(ids);
935
+ spinner.stop();
936
+ if (result.success) {
937
+ console.log('\n' + chalk_1.default.green('╔══════════════════════════════════════════╗'));
938
+ console.log(chalk_1.default.green('║') + chalk_1.default.bold.white(' ✓ PAYOUTS APPROVED & SUBMITTED ') + chalk_1.default.green('║'));
939
+ console.log(chalk_1.default.green('╠══════════════════════════════════════════╣'));
940
+ console.log(chalk_1.default.green('║') + ` Successful: ${chalk_1.default.bold.green(result.success_count)}`.padEnd(42) + chalk_1.default.green('║'));
941
+ console.log(chalk_1.default.green('║') + ` Failed: ${chalk_1.default.bold.red(result.failed_count)}`.padEnd(42) + chalk_1.default.green('║'));
942
+ console.log(chalk_1.default.green('║') + ` Total: ${chalk_1.default.bold.yellow('$' + result.total_amount.toFixed(2))}`.padEnd(42) + chalk_1.default.green('║'));
943
+ console.log(chalk_1.default.green('╚══════════════════════════════════════════╝\n'));
944
+ if (result.errors && result.errors.length > 0) {
945
+ console.log(chalk_1.default.red(' Errors:'));
946
+ result.errors.forEach((err) => {
947
+ console.log(chalk_1.default.dim(` - ${err}`));
948
+ });
949
+ console.log('');
950
+ }
951
+ }
952
+ else {
953
+ console.log(chalk_1.default.red(`\n Failed: ${result.error || 'Unknown error'}\n`));
954
+ }
955
+ }
956
+ catch (error) {
957
+ spinner.fail(chalk_1.default.red('Failed to approve payouts'));
958
+ console.log(chalk_1.default.dim(` ${error.response?.data?.error || error.message}\n`));
959
+ }
960
+ };
961
+ const cancelPayoutsCmd = async (ids) => {
962
+ if (ids.length === 0) {
963
+ console.log(chalk_1.default.red('\n No payout IDs provided\n'));
964
+ return;
965
+ }
966
+ // Ask for cooldown options
967
+ const { confirm, addCooldown, cooldownHours, cooldownReason } = await inquirer_1.default.prompt([
968
+ {
969
+ type: 'confirm',
970
+ name: 'confirm',
971
+ message: chalk_1.default.yellow(`⚠️ Cancel ${ids.length} payout(s) and return funds to wallets?`),
972
+ default: false,
973
+ },
974
+ {
975
+ type: 'confirm',
976
+ name: 'addCooldown',
977
+ message: 'Add withdrawal cooldown for these users?',
978
+ default: false,
979
+ when: (answers) => answers.confirm,
980
+ },
981
+ {
982
+ type: 'list',
983
+ name: 'cooldownHours',
984
+ message: 'Cooldown duration:',
985
+ choices: [
986
+ { name: '24 hours', value: 24 },
987
+ { name: '48 hours', value: 48 },
988
+ { name: '72 hours', value: 72 },
989
+ { name: '1 week', value: 168 },
990
+ ],
991
+ when: (answers) => answers.addCooldown,
992
+ },
993
+ {
994
+ type: 'input',
995
+ name: 'cooldownReason',
996
+ message: 'Reason for cancellation:',
997
+ default: 'Payout cancelled by admin',
998
+ when: (answers) => answers.addCooldown,
999
+ },
1000
+ ]);
1001
+ if (!confirm) {
1002
+ console.log(chalk_1.default.dim('\n Cancelled\n'));
1003
+ return;
1004
+ }
1005
+ const spinner = (0, ora_1.default)(`Cancelling ${ids.length} payouts...`).start();
1006
+ try {
1007
+ const options = {};
1008
+ if (addCooldown) {
1009
+ options.cooldown_hours = cooldownHours;
1010
+ options.cooldown_reason = cooldownReason;
1011
+ }
1012
+ const result = await api_1.api.batchCancelPayouts(ids, options);
1013
+ spinner.stop();
1014
+ if (result.success) {
1015
+ console.log('\n' + chalk_1.default.yellow('╔══════════════════════════════════════════╗'));
1016
+ console.log(chalk_1.default.yellow('║') + chalk_1.default.bold.white(' ↩ PAYOUTS CANCELLED & RETURNED ') + chalk_1.default.yellow('║'));
1017
+ console.log(chalk_1.default.yellow('╠══════════════════════════════════════════╣'));
1018
+ console.log(chalk_1.default.yellow('║') + ` Cancelled: ${chalk_1.default.bold.green(result.success_count)}`.padEnd(42) + chalk_1.default.yellow('║'));
1019
+ console.log(chalk_1.default.yellow('║') + ` Failed: ${chalk_1.default.bold.red(result.failed_count)}`.padEnd(42) + chalk_1.default.yellow('║'));
1020
+ console.log(chalk_1.default.yellow('║') + ` Returned: ${chalk_1.default.bold.green('$' + result.total_amount.toFixed(2))}`.padEnd(42) + chalk_1.default.yellow('║'));
1021
+ console.log(chalk_1.default.yellow('╚══════════════════════════════════════════╝\n'));
1022
+ if (result.errors && result.errors.length > 0) {
1023
+ console.log(chalk_1.default.red(' Errors:'));
1024
+ result.errors.forEach((err) => {
1025
+ console.log(chalk_1.default.dim(` - Payout ${err.payout_id}: ${err.error}`));
1026
+ });
1027
+ console.log('');
1028
+ }
1029
+ }
1030
+ else {
1031
+ console.log(chalk_1.default.red(`\n Failed: ${result.error || 'Unknown error'}\n`));
1032
+ }
1033
+ }
1034
+ catch (error) {
1035
+ spinner.fail(chalk_1.default.red('Failed to cancel payouts'));
1036
+ console.log(chalk_1.default.dim(` ${error.response?.data?.error || error.message}\n`));
1037
+ }
1038
+ };
1039
+ const selectPayoutsInteractive = async (plan) => {
1040
+ const spinner = (0, ora_1.default)('Loading payouts...').start();
1041
+ try {
1042
+ const data = await api_1.api.listPayouts({ plan, status: 'pending', limit: 100 });
1043
+ const payouts = data.data || [];
1044
+ spinner.stop();
1045
+ if (payouts.length === 0) {
1046
+ console.log(chalk_1.default.dim('\n No pending payouts found\n'));
1047
+ return [];
1048
+ }
1049
+ // Group by plan for better display
1050
+ const choices = payouts.map((p) => {
1051
+ const planColor = PLAN_COLORS[p.plan] || chalk_1.default.white;
1052
+ const planIcon = PLAN_ICONS[p.plan] || '📋';
1053
+ return {
1054
+ name: `${planIcon} ${chalk_1.default.dim('#' + p.id)} ${planColor(p.plan.padEnd(12))} ${p.user_email.substring(0, 25).padEnd(25)} ${chalk_1.default.green('$' + p.amount.toFixed(2).padStart(10))} ${chalk_1.default.dim(p.crypto_type)}`,
1055
+ value: p.id,
1056
+ short: `#${p.id}`,
1057
+ };
1058
+ });
1059
+ const { selected } = await inquirer_1.default.prompt([
1060
+ {
1061
+ type: 'checkbox',
1062
+ name: 'selected',
1063
+ message: 'Select payouts to process:',
1064
+ choices,
1065
+ pageSize: 15,
1066
+ loop: false,
1067
+ },
1068
+ ]);
1069
+ return selected;
1070
+ }
1071
+ catch (error) {
1072
+ spinner.fail(chalk_1.default.red('Failed to load payouts'));
1073
+ return [];
1074
+ }
1075
+ };
1076
+ const processPayoutsWithProgress = async (ids, action) => {
1077
+ console.log('\n' + chalk_1.default.cyan('╔══════════════════════════════════════════════════════════════╗'));
1078
+ console.log(chalk_1.default.cyan('║') + chalk_1.default.bold.white(` 🔄 PROCESSING ${ids.length} PAYOUT(S)... `) + chalk_1.default.cyan('║'));
1079
+ console.log(chalk_1.default.cyan('╠══════════════════════════════════════════════════════════════╣'));
1080
+ const startTime = Date.now();
1081
+ // Show progress
1082
+ let processed = 0;
1083
+ const progressBar = (current, total) => {
1084
+ const percent = Math.round((current / total) * 100);
1085
+ const filled = Math.round(percent / 2);
1086
+ const empty = 50 - filled;
1087
+ return chalk_1.default.green('█'.repeat(filled)) + chalk_1.default.dim('░'.repeat(empty)) + ` ${percent}%`;
1088
+ };
1089
+ // Simulate progress while waiting for API
1090
+ const progressInterval = setInterval(() => {
1091
+ processed = Math.min(processed + Math.random() * 10, 90);
1092
+ process.stdout.write(`\r${chalk_1.default.cyan('║')} ${progressBar(processed, 100)} ${chalk_1.default.cyan('║')}`);
1093
+ }, 200);
1094
+ try {
1095
+ let result;
1096
+ if (action === 'approve') {
1097
+ result = await api_1.api.batchApprovePayouts(ids);
1098
+ }
1099
+ else {
1100
+ result = await api_1.api.batchCancelPayouts(ids);
1101
+ }
1102
+ clearInterval(progressInterval);
1103
+ processed = 100;
1104
+ process.stdout.write(`\r${chalk_1.default.cyan('║')} ${progressBar(100, 100)} ${chalk_1.default.cyan('║')}\n`);
1105
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
1106
+ console.log(chalk_1.default.cyan('╠══════════════════════════════════════════════════════════════╣'));
1107
+ if (result.success) {
1108
+ const icon = action === 'approve' ? '✓' : '↩';
1109
+ const verb = action === 'approve' ? 'APPROVED & SENT' : 'CANCELLED & RETURNED';
1110
+ console.log(chalk_1.default.cyan('║') + chalk_1.default.green(` ${icon} ${verb} `) + chalk_1.default.cyan('║'));
1111
+ console.log(chalk_1.default.cyan('║') + ` Successful: ${chalk_1.default.bold.green(String(result.success_count).padEnd(5))} Failed: ${chalk_1.default.bold.red(String(result.failed_count).padEnd(5))} Time: ${chalk_1.default.dim(elapsed + 's')}`.padEnd(62) + chalk_1.default.cyan('║'));
1112
+ console.log(chalk_1.default.cyan('║') + ` Total Amount: ${chalk_1.default.bold.yellow('$' + result.total_amount.toFixed(2))}`.padEnd(62) + chalk_1.default.cyan('║'));
1113
+ }
1114
+ else {
1115
+ console.log(chalk_1.default.cyan('║') + chalk_1.default.red(` ✗ FAILED: ${result.error || 'Unknown error'}`.substring(0, 58).padEnd(60)) + chalk_1.default.cyan('║'));
1116
+ }
1117
+ console.log(chalk_1.default.cyan('╚══════════════════════════════════════════════════════════════╝\n'));
1118
+ // Show errors if any
1119
+ if (result.errors && result.errors.length > 0) {
1120
+ console.log(chalk_1.default.red(' Errors:'));
1121
+ result.errors.slice(0, 5).forEach((err) => {
1122
+ const errMsg = typeof err === 'string' ? err : `Payout ${err.payout_id}: ${err.error}`;
1123
+ console.log(chalk_1.default.dim(` - ${errMsg}`));
1124
+ });
1125
+ if (result.errors.length > 5) {
1126
+ console.log(chalk_1.default.dim(` ... and ${result.errors.length - 5} more errors`));
1127
+ }
1128
+ console.log('');
1129
+ }
1130
+ return result;
1131
+ }
1132
+ catch (error) {
1133
+ clearInterval(progressInterval);
1134
+ console.log(chalk_1.default.cyan('║') + chalk_1.default.red(' ✗ ERROR: ' + (error.response?.data?.error || error.message).substring(0, 50).padEnd(52)) + chalk_1.default.cyan('║'));
1135
+ console.log(chalk_1.default.cyan('╚══════════════════════════════════════════════════════════════╝\n'));
1136
+ return { success: false };
1137
+ }
1138
+ };
1139
+ const runPayoutsShell = async () => {
1140
+ setTitle('Payouts');
1141
+ await showPayoutDashboard();
1142
+ const runLoop = async () => {
1143
+ const { command } = await inquirer_1.default.prompt([
1144
+ {
1145
+ type: 'input',
1146
+ name: 'command',
1147
+ message: chalk_1.default.yellow('payouts') + chalk_1.default.cyan(' > '),
1148
+ prefix: '',
1149
+ },
1150
+ ]);
1151
+ const parts = command.trim().split(/\s+/);
1152
+ const cmd = parts[0]?.toLowerCase();
1153
+ const args = parts.slice(1);
1154
+ if (cmd === 'back' || cmd === 'exit' || cmd === 'q') {
1155
+ setTitle('Home');
1156
+ return;
1157
+ }
1158
+ if (cmd === '') {
1159
+ return runLoop();
1160
+ }
1161
+ try {
1162
+ switch (cmd) {
1163
+ case 'refresh':
1164
+ case 'r':
1165
+ await showPayoutDashboard();
1166
+ break;
1167
+ case 'list':
1168
+ case 'ls':
1169
+ const listPlan = args.find((a) => !a.startsWith('-'));
1170
+ await listPayoutsCmd({ plan: listPlan });
1171
+ break;
1172
+ case 'select':
1173
+ case 's':
1174
+ // Interactive selection mode
1175
+ const selectPlan = args.find((a) => !a.startsWith('-'));
1176
+ const selectedIds = await selectPayoutsInteractive(selectPlan);
1177
+ if (selectedIds.length > 0) {
1178
+ const { action } = await inquirer_1.default.prompt([
1179
+ {
1180
+ type: 'list',
1181
+ name: 'action',
1182
+ message: `What do you want to do with ${selectedIds.length} selected payout(s)?`,
1183
+ choices: [
1184
+ { name: chalk_1.default.green('✓ Approve & Send via TarPay'), value: 'approve' },
1185
+ { name: chalk_1.default.yellow('↩ Cancel & Return to Wallets'), value: 'cancel' },
1186
+ { name: chalk_1.default.dim('✗ Cancel'), value: 'none' },
1187
+ ],
1188
+ },
1189
+ ]);
1190
+ if (action === 'approve') {
1191
+ const { confirm } = await inquirer_1.default.prompt([
1192
+ {
1193
+ type: 'confirm',
1194
+ name: 'confirm',
1195
+ message: chalk_1.default.yellow(`⚠️ Confirm: Send ${selectedIds.length} payout(s)?`),
1196
+ default: false,
1197
+ },
1198
+ ]);
1199
+ if (confirm) {
1200
+ await processPayoutsWithProgress(selectedIds, 'approve');
1201
+ }
1202
+ }
1203
+ else if (action === 'cancel') {
1204
+ const { confirm } = await inquirer_1.default.prompt([
1205
+ {
1206
+ type: 'confirm',
1207
+ name: 'confirm',
1208
+ message: chalk_1.default.yellow(`⚠️ Confirm: Cancel ${selectedIds.length} payout(s)?`),
1209
+ default: false,
1210
+ },
1211
+ ]);
1212
+ if (confirm) {
1213
+ await processPayoutsWithProgress(selectedIds, 'cancel');
1214
+ }
1215
+ }
1216
+ }
1217
+ break;
1218
+ case 'approve':
1219
+ case 'a':
1220
+ if (args.length === 0) {
1221
+ // Interactive mode
1222
+ const approveSelected = await selectPayoutsInteractive();
1223
+ if (approveSelected.length > 0) {
1224
+ const { confirm } = await inquirer_1.default.prompt([
1225
+ {
1226
+ type: 'confirm',
1227
+ name: 'confirm',
1228
+ message: chalk_1.default.yellow(`⚠️ Approve & send ${approveSelected.length} payout(s)?`),
1229
+ default: false,
1230
+ },
1231
+ ]);
1232
+ if (confirm) {
1233
+ await processPayoutsWithProgress(approveSelected, 'approve');
1234
+ }
1235
+ }
1236
+ }
1237
+ else {
1238
+ const approveIds = args.map(Number).filter((n) => !isNaN(n));
1239
+ await processPayoutsWithProgress(approveIds, 'approve');
1240
+ }
1241
+ break;
1242
+ case 'cancel':
1243
+ case 'c':
1244
+ if (args.length === 0) {
1245
+ // Interactive mode
1246
+ const cancelSelected = await selectPayoutsInteractive();
1247
+ if (cancelSelected.length > 0) {
1248
+ const { confirm } = await inquirer_1.default.prompt([
1249
+ {
1250
+ type: 'confirm',
1251
+ name: 'confirm',
1252
+ message: chalk_1.default.yellow(`⚠️ Cancel ${cancelSelected.length} payout(s)?`),
1253
+ default: false,
1254
+ },
1255
+ ]);
1256
+ if (confirm) {
1257
+ await processPayoutsWithProgress(cancelSelected, 'cancel');
1258
+ }
1259
+ }
1260
+ }
1261
+ else {
1262
+ const cancelIds = args.map(Number).filter((n) => !isNaN(n));
1263
+ await processPayoutsWithProgress(cancelIds, 'cancel');
1264
+ }
1265
+ break;
1266
+ case 'hermes':
1267
+ case 'alpha':
1268
+ case 'mematic':
1269
+ case 'booster':
1270
+ case 'validator_v2':
1271
+ await listPayoutsCmd({ plan: cmd });
1272
+ break;
1273
+ case 'process':
1274
+ // Process specific plan with interactive selection
1275
+ const { processPlan } = await inquirer_1.default.prompt([
1276
+ {
1277
+ type: 'list',
1278
+ name: 'processPlan',
1279
+ message: 'Select plan to process:',
1280
+ choices: [
1281
+ { name: '⚡ Hermes', value: 'hermes' },
1282
+ { name: '🔷 Alpha', value: 'alpha' },
1283
+ { name: '💎 Mematic', value: 'mematic' },
1284
+ { name: '🔐 Validator V2', value: 'validator_v2' },
1285
+ { name: '🚀 Booster', value: 'booster' },
1286
+ { name: '📋 All Plans', value: undefined },
1287
+ ],
1288
+ },
1289
+ ]);
1290
+ const toProcess = await selectPayoutsInteractive(processPlan);
1291
+ if (toProcess.length > 0) {
1292
+ const { confirmProcess } = await inquirer_1.default.prompt([
1293
+ {
1294
+ type: 'confirm',
1295
+ name: 'confirmProcess',
1296
+ message: chalk_1.default.yellow(`⚠️ Approve & send ${toProcess.length} payout(s)?`),
1297
+ default: false,
1298
+ },
1299
+ ]);
1300
+ if (confirmProcess) {
1301
+ await processPayoutsWithProgress(toProcess, 'approve');
1302
+ }
1303
+ }
1304
+ break;
1305
+ case 'all':
1306
+ // Approve ALL pending payouts
1307
+ const allSpinner = (0, ora_1.default)('Loading all pending payouts...').start();
1308
+ try {
1309
+ const allData = await api_1.api.listPayouts({ status: 'pending', limit: 500 });
1310
+ const allPayouts = allData.data || [];
1311
+ allSpinner.stop();
1312
+ if (allPayouts.length === 0) {
1313
+ console.log(chalk_1.default.green('\n ✓ No pending payouts to approve\n'));
1314
+ break;
1315
+ }
1316
+ const totalAmount = allPayouts.reduce((sum, p) => sum + p.amount, 0);
1317
+ console.log(chalk_1.default.yellow(`\n ⚠️ APPROVE ALL: ${allPayouts.length} payouts totaling $${totalAmount.toFixed(2)}\n`));
1318
+ const { confirmAll } = await inquirer_1.default.prompt([
1319
+ {
1320
+ type: 'confirm',
1321
+ name: 'confirmAll',
1322
+ message: chalk_1.default.red.bold(`Are you sure you want to approve ALL ${allPayouts.length} pending payouts?`),
1323
+ default: false,
1324
+ },
1325
+ ]);
1326
+ if (confirmAll) {
1327
+ const allIds = allPayouts.map((p) => p.id);
1328
+ await processPayoutsWithProgress(allIds, 'approve');
1329
+ }
1330
+ else {
1331
+ console.log(chalk_1.default.dim('\n Cancelled\n'));
1332
+ }
1333
+ }
1334
+ catch (e) {
1335
+ allSpinner.fail(chalk_1.default.red('Failed to load payouts'));
1336
+ }
1337
+ break;
1338
+ case 'help':
1339
+ case '?':
1340
+ console.log(chalk_1.default.cyan('\n Payout Commands:'));
1341
+ console.log(chalk_1.default.dim(' ────────────────────'));
1342
+ console.log(' refresh, r Refresh dashboard');
1343
+ console.log(' list [plan] List pending payouts');
1344
+ console.log(' select [plan] Interactive payout selection');
1345
+ console.log(' approve [ids] Approve payouts (interactive if no IDs)');
1346
+ console.log(chalk_1.default.yellow(' all Approve ALL pending payouts'));
1347
+ console.log(' cancel [ids] Cancel payouts (interactive if no IDs)');
1348
+ console.log(' process Process payouts by plan (interactive)');
1349
+ console.log(' hermes/alpha/etc List payouts for specific plan');
1350
+ console.log(' back, q Return to main menu');
1351
+ console.log('');
1352
+ break;
1353
+ default:
1354
+ console.log(chalk_1.default.red(` Unknown command: ${cmd}`));
1355
+ console.log(chalk_1.default.dim(' Type "help" for available commands\n'));
1356
+ }
1357
+ }
1358
+ catch (e) {
1359
+ console.log(chalk_1.default.red(` Error: ${e.message}\n`));
1360
+ }
1361
+ await runLoop();
1362
+ };
1363
+ await runLoop();
1364
+ };
1365
+ // ==================== LOGIN ====================
1366
+ program
1367
+ .command('login')
1368
+ .description('Authenticate with Mission Control via Google SSO')
1369
+ .option('-t, --token <token>', 'API token (skip browser login)')
1370
+ .option('--type <type>', 'Token type (bearer or token)', 'bearer')
1371
+ .option('--url <url>', 'API URL', 'https://api.targlobal.org')
1372
+ .action(async (options) => {
1373
+ setTitle('Login');
1374
+ let token = options.token;
1375
+ if (!token) {
1376
+ console.log(miniLogo);
1377
+ console.log('');
1378
+ console.log(chalk_1.default.cyan(' Opening browser for Google SSO login...'));
1379
+ console.log('');
1380
+ const authUrl = 'https://agents.targlobal.org/cli-auth';
1381
+ try {
1382
+ const open = (await Promise.resolve().then(() => __importStar(require('open')))).default;
1383
+ await open(authUrl);
1384
+ console.log(chalk_1.default.dim(` If browser doesn't open, visit:`));
1385
+ console.log(chalk_1.default.white(` ${authUrl}`));
1386
+ console.log('');
1387
+ }
1388
+ catch (e) {
1389
+ console.log(chalk_1.default.dim(` Open this URL in your browser:`));
1390
+ console.log(chalk_1.default.white(` ${authUrl}`));
1391
+ console.log('');
1392
+ }
1393
+ const answers = await inquirer_1.default.prompt([
1394
+ {
1395
+ type: 'password',
1396
+ name: 'token',
1397
+ message: 'Paste your token from the browser:',
1398
+ mask: '*',
1399
+ },
1400
+ ]);
1401
+ token = answers.token;
1402
+ options.type = 'bearer';
1403
+ }
1404
+ (0, config_1.setConfig)('token', token);
1405
+ (0, config_1.setConfig)('tokenType', options.type);
1406
+ (0, config_1.setConfig)('apiUrl', options.url);
1407
+ (0, api_1.resetApiClient)();
1408
+ const spinner = (0, ora_1.default)('Verifying credentials...').start();
1409
+ try {
1410
+ // Fetch user info and stats
1411
+ await fetchUserInfo();
1412
+ const stats = await api_1.api.getStats();
1413
+ spinner.succeed(chalk_1.default.green('Authenticated successfully!'));
1414
+ const user = (0, config_1.getUser)();
1415
+ // Show welcome dashboard
1416
+ console.log('');
1417
+ console.log(chalk_1.default.cyan('╔════════════════════════════════════════════════════════════════╗'));
1418
+ console.log(chalk_1.default.cyan('║') + chalk_1.default.bold.white(` Welcome back, ${(user?.name || 'Agent').padEnd(45)}`) + chalk_1.default.cyan('║'));
1419
+ console.log(chalk_1.default.cyan('╠════════════════════════════════════════════════════════════════╣'));
1420
+ console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.yellow('⚡')} My Tasks: ${chalk_1.default.bold.white(String(stats.my_tasks).padEnd(8))} ${chalk_1.default.red('●')} Critical: ${chalk_1.default.bold.red(String(stats.critical_count).padEnd(8))} ${chalk_1.default.yellow('!')} Overdue: ${chalk_1.default.bold.yellow(String(stats.overdue_tasks))}`.padEnd(71) + chalk_1.default.cyan('║'));
1421
+ console.log(chalk_1.default.cyan('╚════════════════════════════════════════════════════════════════╝'));
1422
+ console.log('');
1423
+ // Ask if they want to enter interactive mode
1424
+ const { startShell } = await inquirer_1.default.prompt([
1425
+ {
1426
+ type: 'confirm',
1427
+ name: 'startShell',
1428
+ message: 'Enter Mission Control?',
1429
+ default: true,
1430
+ },
1431
+ ]);
1432
+ if (startShell) {
1433
+ // Launch interactive shell
1434
+ await runInteractiveShell();
1435
+ }
1436
+ }
1437
+ catch (error) {
1438
+ spinner.fail(chalk_1.default.red('Authentication failed'));
1439
+ (0, config_1.clearConfig)();
1440
+ console.log(chalk_1.default.dim(' Check your token and try again\n'));
1441
+ }
1442
+ });
1443
+ // ==================== LOGOUT ====================
1444
+ program
1445
+ .command('logout')
1446
+ .description('Clear stored credentials')
1447
+ .action(() => {
1448
+ (0, config_1.clearConfig)();
1449
+ console.log(chalk_1.default.green('\n[OK] Logged out successfully\n'));
1450
+ });
1451
+ // ==================== UPDATE ====================
1452
+ program
1453
+ .command('update')
1454
+ .description('Update Mission Control CLI to latest version')
1455
+ .action(async () => {
1456
+ setTitle('Updating');
1457
+ console.log(miniLogo);
1458
+ console.log('');
1459
+ const spinner = (0, ora_1.default)('Checking for updates...').start();
1460
+ try {
1461
+ // Re-run the installer
1462
+ spinner.text = 'Downloading latest version...';
1463
+ (0, child_process_1.execSync)('curl -fsSL https://targlobal.org/download/mc | bash', {
1464
+ stdio: 'inherit',
1465
+ });
1466
+ spinner.succeed(chalk_1.default.green('Updated successfully!'));
1467
+ console.log(chalk_1.default.dim(' Restart your terminal to use the new version\n'));
1468
+ }
1469
+ catch (error) {
1470
+ spinner.fail(chalk_1.default.red('Update failed'));
1471
+ console.log(chalk_1.default.dim(' Try manually: curl -fsSL https://targlobal.org/download/mc | bash\n'));
1472
+ }
1473
+ });
1474
+ // ==================== TASKS (list) ====================
1475
+ program
1476
+ .command('tasks')
1477
+ .alias('ls')
1478
+ .description('List your tasks')
1479
+ .option('-a, --all', 'Show all tasks, not just mine')
1480
+ .option('-b, --board <board>', 'Filter by board')
1481
+ .option('-p, --priority <priority>', 'Filter by priority')
1482
+ .action(async (options) => {
1483
+ setTitle('Tasks');
1484
+ requireAuth();
1485
+ await listTasksCmd(options);
1486
+ showStatusBar();
1487
+ });
1488
+ // ==================== SHOW (task detail) ====================
1489
+ program
1490
+ .command('show <taskId>')
1491
+ .alias('view')
1492
+ .description('Show task details')
1493
+ .action(async (taskId) => {
1494
+ setTitle(`Task ${taskId}`);
1495
+ requireAuth();
1496
+ await showTaskCmd(taskId);
1497
+ showStatusBar();
1498
+ });
1499
+ // ==================== NEW (create task) ====================
1500
+ program
1501
+ .command('new <title>')
1502
+ .alias('create')
1503
+ .description('Create a new task')
1504
+ .option('-d, --description <desc>', 'Task description')
1505
+ .option('-p, --priority <priority>', 'Priority: critical, high, medium, low', 'medium')
1506
+ .option('-t, --type <type>', 'Type: bug, feature, improvement, task', 'task')
1507
+ .option('-b, --board <board>', 'Board slug', 'backend')
1508
+ .action(async (title, options) => {
1509
+ setTitle('New Task');
1510
+ requireAuth();
1511
+ const spinner = (0, ora_1.default)('Creating task...').start();
1512
+ try {
1513
+ const boards = await api_1.api.listBoards();
1514
+ const board = boards.boards.find((b) => b.slug === options.board);
1515
+ if (!board) {
1516
+ spinner.fail(chalk_1.default.red(`Board '${options.board}' not found`));
1517
+ console.log(chalk_1.default.dim(' Available boards: ' + boards.boards.map((b) => b.slug).join(', ') + '\n'));
1518
+ return;
1519
+ }
1520
+ const task = await api_1.api.createTask({
1521
+ title,
1522
+ description: options.description,
1523
+ board: board.id,
1524
+ priority: options.priority,
1525
+ task_type: options.type,
1526
+ });
1527
+ spinner.succeed(chalk_1.default.green(`Task created: ${task.display_id}`));
1528
+ console.log(chalk_1.default.dim(` ${task.title}\n`));
1529
+ }
1530
+ catch (error) {
1531
+ spinner.fail(chalk_1.default.red('Failed to create task'));
1532
+ console.log(chalk_1.default.dim(` ${error.response?.data?.error || error.message}\n`));
1533
+ }
1534
+ showStatusBar();
1535
+ });
1536
+ // ==================== START (move to In Progress) ====================
1537
+ program
1538
+ .command('start <taskId>')
1539
+ .description('Move task to In Progress')
1540
+ .action(async (taskId) => {
1541
+ setTitle('Starting Task');
1542
+ requireAuth();
1543
+ await startTaskCmd(taskId);
1544
+ showStatusBar();
1545
+ });
1546
+ // ==================== DONE (complete task) ====================
1547
+ program
1548
+ .command('done <taskId>')
1549
+ .alias('complete')
1550
+ .description('Mark task as complete')
1551
+ .action(async (taskId) => {
1552
+ setTitle('Completing Task');
1553
+ requireAuth();
1554
+ await completeTaskCmd(taskId);
1555
+ showStatusBar();
1556
+ });
1557
+ // ==================== COMMENT ====================
1558
+ program
1559
+ .command('comment <taskId> <message>')
1560
+ .alias('note')
1561
+ .description('Add a comment to a task')
1562
+ .action(async (taskId, message) => {
1563
+ setTitle('Adding Comment');
1564
+ requireAuth();
1565
+ const spinner = (0, ora_1.default)('Adding comment...').start();
1566
+ try {
1567
+ await api_1.api.addComment(parseTaskNumber(taskId), message);
1568
+ spinner.succeed(chalk_1.default.green('Comment added'));
1569
+ }
1570
+ catch (error) {
1571
+ spinner.fail(chalk_1.default.red('Failed to add comment'));
1572
+ console.log(chalk_1.default.dim(` ${error.response?.data?.error || error.message}\n`));
1573
+ }
1574
+ showStatusBar();
1575
+ });
1576
+ // ==================== BOARDS ====================
1577
+ program
1578
+ .command('boards')
1579
+ .description('List available boards')
1580
+ .action(async () => {
1581
+ setTitle('Boards');
1582
+ requireAuth();
1583
+ await listBoardsCmd();
1584
+ showStatusBar();
1585
+ });
1586
+ // ==================== STATS ====================
1587
+ program
1588
+ .command('stats')
1589
+ .description('Show task statistics')
1590
+ .action(async () => {
1591
+ setTitle('Stats');
1592
+ requireAuth();
1593
+ await showStatsCmd();
1594
+ showStatusBar();
1595
+ });
1596
+ // ==================== URGENT ====================
1597
+ program
1598
+ .command('urgent')
1599
+ .description('Show critical and overdue tasks')
1600
+ .action(async () => {
1601
+ setTitle('Urgent');
1602
+ requireAuth();
1603
+ await showUrgentCmd();
1604
+ showStatusBar();
1605
+ });
1606
+ // ==================== WHOAMI ====================
1607
+ program
1608
+ .command('whoami')
1609
+ .description('Show current user and configuration')
1610
+ .action(() => {
1611
+ setTitle('Who Am I');
1612
+ showWhoami();
1613
+ });
1614
+ // ==================== CONFIG ====================
1615
+ program
1616
+ .command('config [key] [value]')
1617
+ .description('View or set configuration (compact: auto/on/off)')
1618
+ .action((key, value) => {
1619
+ setTitle('Config');
1620
+ const config = (0, config_1.getConfig)();
1621
+ if (!key) {
1622
+ // Show all config
1623
+ console.log('\n' + chalk_1.default.bold(' Mission Control Config'));
1624
+ console.log(chalk_1.default.dim(' ──────────────────────'));
1625
+ console.log(` compact: ${chalk_1.default.cyan(config.compact)} ${chalk_1.default.dim('(auto/on/off)')}`);
1626
+ console.log(` apiUrl: ${config.apiUrl}`);
1627
+ console.log(` token: ${config.token ? chalk_1.default.green('●') + ' set' : chalk_1.default.red('○') + ' not set'}`);
1628
+ console.log('');
1629
+ console.log(chalk_1.default.dim(' Usage: mc config <key> <value>'));
1630
+ console.log(chalk_1.default.dim(' Example: mc config compact on'));
1631
+ console.log('');
1632
+ return;
1633
+ }
1634
+ if (key === 'compact') {
1635
+ if (!value || !['auto', 'on', 'off'].includes(value)) {
1636
+ console.log(chalk_1.default.red('\n Invalid value. Use: auto, on, or off\n'));
1637
+ return;
1638
+ }
1639
+ (0, config_1.setConfig)('compact', value);
1640
+ console.log(chalk_1.default.green(`\n ✓ Compact mode set to: ${value}\n`));
1641
+ if (value === 'on') {
1642
+ console.log(chalk_1.default.dim(' Mobile-friendly compact UI enabled'));
1643
+ }
1644
+ else if (value === 'off') {
1645
+ console.log(chalk_1.default.dim(' Full desktop UI enabled'));
1646
+ }
1647
+ else {
1648
+ console.log(chalk_1.default.dim(' Will auto-detect based on terminal width (<60 = compact)'));
1649
+ }
1650
+ console.log('');
1651
+ }
1652
+ else {
1653
+ console.log(chalk_1.default.red(`\n Unknown config key: ${key}`));
1654
+ console.log(chalk_1.default.dim(' Available keys: compact\n'));
1655
+ }
1656
+ });
1657
+ // ==================== PAYOUTS (Admin) ====================
1658
+ program
1659
+ .command('payouts')
1660
+ .alias('pay')
1661
+ .description('Payout processing dashboard (managers/executors only)')
1662
+ .option('-l, --list', 'List pending payouts')
1663
+ .option('-p, --plan <plan>', 'Filter by plan (hermes, alpha, mematic, validator_v2, booster)')
1664
+ .option('-a, --approve <ids...>', 'Approve payout IDs')
1665
+ .option('-c, --cancel <ids...>', 'Cancel payout IDs')
1666
+ .action(async (options) => {
1667
+ setTitle('Payouts');
1668
+ requireAuth();
1669
+ if (options.list) {
1670
+ await listPayoutsCmd({ plan: options.plan });
1671
+ }
1672
+ else if (options.approve) {
1673
+ const ids = options.approve.map(Number).filter((n) => !isNaN(n));
1674
+ if (ids.length > 0) {
1675
+ await processPayoutsWithProgress(ids, 'approve');
1676
+ }
1677
+ }
1678
+ else if (options.cancel) {
1679
+ const ids = options.cancel.map(Number).filter((n) => !isNaN(n));
1680
+ if (ids.length > 0) {
1681
+ await processPayoutsWithProgress(ids, 'cancel');
1682
+ }
1683
+ }
1684
+ else {
1685
+ // Interactive dashboard mode
1686
+ await runPayoutsShell();
1687
+ }
1688
+ showStatusBar();
1689
+ });
1690
+ // Default action - show help or run shell if authenticated
1691
+ if (process.argv.length === 2) {
1692
+ if ((0, config_1.isAuthenticated)()) {
1693
+ // Run interactive shell
1694
+ process.argv.push('shell');
1695
+ }
1696
+ else {
1697
+ // Show help
1698
+ program.outputHelp();
1699
+ }
1700
+ }
1701
+ // Parse and run
1702
+ program.parse();
1703
+ //# sourceMappingURL=index.js.map