@ebowwa/crm 0.1.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 +174 -0
- package/dist/cli/commands/activities.d.ts +11 -0
- package/dist/cli/commands/activities.d.ts.map +1 -0
- package/dist/cli/commands/activities.js +427 -0
- package/dist/cli/commands/activities.js.map +1 -0
- package/dist/cli/commands/contacts.d.ts +11 -0
- package/dist/cli/commands/contacts.d.ts.map +1 -0
- package/dist/cli/commands/contacts.js +458 -0
- package/dist/cli/commands/contacts.js.map +1 -0
- package/dist/cli/commands/deals.d.ts +11 -0
- package/dist/cli/commands/deals.d.ts.map +1 -0
- package/dist/cli/commands/deals.js +498 -0
- package/dist/cli/commands/deals.js.map +1 -0
- package/dist/cli/commands/media.d.ts +11 -0
- package/dist/cli/commands/media.d.ts.map +1 -0
- package/dist/cli/commands/media.js +417 -0
- package/dist/cli/commands/media.js.map +1 -0
- package/dist/cli/commands/search.d.ts +11 -0
- package/dist/cli/commands/search.d.ts.map +1 -0
- package/dist/cli/commands/search.js +346 -0
- package/dist/cli/commands/search.js.map +1 -0
- package/dist/cli/index.d.ts +13 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +173 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/repl.d.ts +15 -0
- package/dist/cli/repl.d.ts.map +1 -0
- package/dist/cli/repl.js +318 -0
- package/dist/cli/repl.js.map +1 -0
- package/dist/cli/utils/config.d.ts +91 -0
- package/dist/cli/utils/config.d.ts.map +1 -0
- package/dist/cli/utils/config.js +212 -0
- package/dist/cli/utils/config.js.map +1 -0
- package/dist/cli/utils/output.d.ts +136 -0
- package/dist/cli/utils/output.d.ts.map +1 -0
- package/dist/cli/utils/output.js +323 -0
- package/dist/cli/utils/output.js.map +1 -0
- package/dist/cli/utils/prompt.d.ts +81 -0
- package/dist/cli/utils/prompt.d.ts.map +1 -0
- package/dist/cli/utils/prompt.js +341 -0
- package/dist/cli/utils/prompt.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +32 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/schemas.d.ts +3050 -0
- package/dist/core/schemas.d.ts.map +1 -0
- package/dist/core/schemas.js +667 -0
- package/dist/core/schemas.js.map +1 -0
- package/dist/core/types.d.ts +597 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +8 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +14 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +11 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +13 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +18 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/storage/client.d.ts +109 -0
- package/dist/mcp/storage/client.d.ts.map +1 -0
- package/dist/mcp/storage/client.js +355 -0
- package/dist/mcp/storage/client.js.map +1 -0
- package/dist/mcp/storage/index.d.ts +7 -0
- package/dist/mcp/storage/index.d.ts.map +1 -0
- package/dist/mcp/storage/index.js +6 -0
- package/dist/mcp/storage/index.js.map +1 -0
- package/dist/mcp/storage/types.d.ts +44 -0
- package/dist/mcp/storage/types.d.ts.map +1 -0
- package/dist/mcp/storage/types.js +35 -0
- package/dist/mcp/storage/types.js.map +1 -0
- package/dist/mcp/tools/definitions.d.ts +16 -0
- package/dist/mcp/tools/definitions.d.ts.map +1 -0
- package/dist/mcp/tools/definitions.js +914 -0
- package/dist/mcp/tools/definitions.js.map +1 -0
- package/dist/mcp/tools/handlers.d.ts +50 -0
- package/dist/mcp/tools/handlers.d.ts.map +1 -0
- package/dist/mcp/tools/handlers.js +760 -0
- package/dist/mcp/tools/handlers.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +7 -0
- package/dist/mcp/tools/index.d.ts.map +1 -0
- package/dist/mcp/tools/index.js +6 -0
- package/dist/mcp/tools/index.js.map +1 -0
- package/dist/mcp/tools/types.d.ts +314 -0
- package/dist/mcp/tools/types.d.ts.map +1 -0
- package/dist/mcp/tools/types.js +5 -0
- package/dist/mcp/tools/types.js.map +1 -0
- package/dist/mcp/transports/stdio.d.ts +27 -0
- package/dist/mcp/transports/stdio.d.ts.map +1 -0
- package/dist/mcp/transports/stdio.js +237 -0
- package/dist/mcp/transports/stdio.js.map +1 -0
- package/dist/telemetry/index.d.ts +58 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +109 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/logger.d.ts +116 -0
- package/dist/telemetry/logger.d.ts.map +1 -0
- package/dist/telemetry/logger.js +256 -0
- package/dist/telemetry/logger.js.map +1 -0
- package/dist/telemetry/metrics.d.ts +115 -0
- package/dist/telemetry/metrics.d.ts.map +1 -0
- package/dist/telemetry/metrics.js +292 -0
- package/dist/telemetry/metrics.js.map +1 -0
- package/dist/telemetry/tracer.d.ts +227 -0
- package/dist/telemetry/tracer.d.ts.map +1 -0
- package/dist/telemetry/tracer.js +355 -0
- package/dist/telemetry/tracer.js.map +1 -0
- package/dist/web/app.d.ts +2 -0
- package/dist/web/app.d.ts.map +1 -0
- package/dist/web/app.js +115 -0
- package/dist/web/app.js.map +1 -0
- package/dist/web/components/ContactList.d.ts +3 -0
- package/dist/web/components/ContactList.d.ts.map +1 -0
- package/dist/web/components/ContactList.js +262 -0
- package/dist/web/components/ContactList.js.map +1 -0
- package/dist/web/components/Dashboard.d.ts +3 -0
- package/dist/web/components/Dashboard.d.ts.map +1 -0
- package/dist/web/components/Dashboard.js +158 -0
- package/dist/web/components/Dashboard.js.map +1 -0
- package/dist/web/components/DealPipeline.d.ts +3 -0
- package/dist/web/components/DealPipeline.d.ts.map +1 -0
- package/dist/web/components/DealPipeline.js +306 -0
- package/dist/web/components/DealPipeline.js.map +1 -0
- package/dist/web/index.d.ts +2 -0
- package/dist/web/index.d.ts.map +1 -0
- package/dist/web/index.js +269 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/types.d.ts +75 -0
- package/dist/web/types.d.ts.map +1 -0
- package/dist/web/types.js +3 -0
- package/dist/web/types.js.map +1 -0
- package/native/index.d.ts +571 -0
- package/native/index.js +687 -0
- package/package.json +105 -0
- package/src/cli/commands/activities.ts +543 -0
- package/src/cli/commands/contacts.ts +563 -0
- package/src/cli/commands/deals.ts +637 -0
- package/src/cli/commands/media.ts +521 -0
- package/src/cli/commands/search.ts +426 -0
- package/src/cli/index.ts +203 -0
- package/src/cli/repl.ts +379 -0
- package/src/cli/utils/config.ts +299 -0
- package/src/cli/utils/output.ts +386 -0
- package/src/cli/utils/prompt.ts +444 -0
- package/src/cli.ts +11 -0
- package/src/core/index.ts +184 -0
- package/src/core/schemas.ts +770 -0
- package/src/core/types.ts +969 -0
- package/src/index.ts +8 -0
- package/src/mcp/index.ts +17 -0
- package/src/mcp/server.ts +26 -0
- package/src/mcp/storage/client.ts +408 -0
- package/src/mcp/storage/index.ts +7 -0
- package/src/mcp/storage/types.ts +72 -0
- package/src/mcp/tools/definitions.ts +961 -0
- package/src/mcp/tools/handlers.ts +805 -0
- package/src/mcp/tools/index.ts +7 -0
- package/src/mcp/tools/types.ts +390 -0
- package/src/mcp/transports/stdio.ts +225 -0
- package/src/telemetry/index.ts +131 -0
- package/src/telemetry/logger.ts +318 -0
- package/src/telemetry/metrics.ts +393 -0
- package/src/telemetry/tracer.ts +487 -0
- package/src/web/api/activities.ts +41 -0
- package/src/web/api/contacts.ts +114 -0
- package/src/web/api/deals.ts +108 -0
- package/src/web/api/media.ts +98 -0
- package/src/web/app.tsx +143 -0
- package/src/web/components/ActivityFeed.tsx +195 -0
- package/src/web/components/ContactList.tsx +340 -0
- package/src/web/components/Dashboard.tsx +214 -0
- package/src/web/components/DealPipeline.tsx +405 -0
- package/src/web/components/MediaGallery.tsx +334 -0
- package/src/web/index.html +14 -0
- package/src/web/index.ts +326 -0
- package/src/web/styles/main.css +180 -0
- package/src/web/types.ts +311 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Output Formatting Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides colorized output, table formatting, and display helpers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// ANSI color codes
|
|
8
|
+
const colors = {
|
|
9
|
+
reset: '\x1b[0m',
|
|
10
|
+
bold: '\x1b[1m',
|
|
11
|
+
dim: '\x1b[2m',
|
|
12
|
+
italic: '\x1b[3m',
|
|
13
|
+
underline: '\x1b[4m',
|
|
14
|
+
|
|
15
|
+
// Foreground colors
|
|
16
|
+
black: '\x1b[30m',
|
|
17
|
+
red: '\x1b[31m',
|
|
18
|
+
green: '\x1b[32m',
|
|
19
|
+
yellow: '\x1b[33m',
|
|
20
|
+
blue: '\x1b[34m',
|
|
21
|
+
magenta: '\x1b[35m',
|
|
22
|
+
cyan: '\x1b[36m',
|
|
23
|
+
white: '\x1b[37m',
|
|
24
|
+
|
|
25
|
+
// Background colors
|
|
26
|
+
bgBlack: '\x1b[40m',
|
|
27
|
+
bgRed: '\x1b[41m',
|
|
28
|
+
bgGreen: '\x1b[42m',
|
|
29
|
+
bgYellow: '\x1b[43m',
|
|
30
|
+
bgBlue: '\x1b[44m',
|
|
31
|
+
bgMagenta: '\x1b[45m',
|
|
32
|
+
bgCyan: '\x1b[46m',
|
|
33
|
+
bgWhite: '\x1b[47m',
|
|
34
|
+
} as const;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Colorize text with ANSI codes
|
|
38
|
+
*/
|
|
39
|
+
export function colorize(text: string, color: keyof typeof colors): string {
|
|
40
|
+
return `${colors[color]}${text}${colors.reset}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Semantic color helpers
|
|
45
|
+
*/
|
|
46
|
+
export const output = {
|
|
47
|
+
success: (text: string) => colorize(text, 'green'),
|
|
48
|
+
error: (text: string) => colorize(text, 'red'),
|
|
49
|
+
warning: (text: string) => colorize(text, 'yellow'),
|
|
50
|
+
info: (text: string) => colorize(text, 'cyan'),
|
|
51
|
+
dim: (text: string) => colorize(text, 'dim'),
|
|
52
|
+
bold: (text: string) => colorize(text, 'bold'),
|
|
53
|
+
underline: (text: string) => colorize(text, 'underline'),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Print a success message with checkmark
|
|
58
|
+
*/
|
|
59
|
+
export function printSuccess(message: string): void {
|
|
60
|
+
console.log(`${output.success('\u2713')} ${message}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Print an error message with X
|
|
65
|
+
*/
|
|
66
|
+
export function printError(message: string): void {
|
|
67
|
+
console.error(`${output.error('\u2717')} ${message}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Print a warning message with triangle
|
|
72
|
+
*/
|
|
73
|
+
export function printWarning(message: string): void {
|
|
74
|
+
console.log(`${output.warning('\u26a0')} ${message}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Print an info message with bullet
|
|
79
|
+
*/
|
|
80
|
+
export function printInfo(message: string): void {
|
|
81
|
+
console.log(`${output.info('\u2022')} ${message}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Print a header with styling
|
|
86
|
+
*/
|
|
87
|
+
export function printHeader(title: string): void {
|
|
88
|
+
const line = '\u2500'.repeat(title.length + 4);
|
|
89
|
+
console.log();
|
|
90
|
+
console.log(output.bold(`\u250c${line}\u2510`));
|
|
91
|
+
console.log(output.bold(`\u2502 ${title} \u2502`));
|
|
92
|
+
console.log(output.bold(`\u2514${line}\u2518`));
|
|
93
|
+
console.log();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Print a section header
|
|
98
|
+
*/
|
|
99
|
+
export function printSection(title: string): void {
|
|
100
|
+
console.log();
|
|
101
|
+
console.log(output.bold(output.underline(title)));
|
|
102
|
+
console.log();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Format a key-value pair for display
|
|
107
|
+
*/
|
|
108
|
+
export function formatKeyValue(key: string, value: unknown): string {
|
|
109
|
+
const formattedValue =
|
|
110
|
+
value === null || value === undefined
|
|
111
|
+
? output.dim('(none)')
|
|
112
|
+
: String(value);
|
|
113
|
+
return `${output.dim(key)}: ${formattedValue}`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Print key-value pairs
|
|
118
|
+
*/
|
|
119
|
+
export function printKeyValue(
|
|
120
|
+
pairs: Record<string, unknown>,
|
|
121
|
+
indent = 0
|
|
122
|
+
): void {
|
|
123
|
+
const prefix = ' '.repeat(indent);
|
|
124
|
+
for (const [key, value] of Object.entries(pairs)) {
|
|
125
|
+
if (value !== undefined) {
|
|
126
|
+
console.log(`${prefix}${formatKeyValue(key, value)}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Format currency value
|
|
133
|
+
*/
|
|
134
|
+
export function formatCurrency(
|
|
135
|
+
value: number,
|
|
136
|
+
currency = 'USD'
|
|
137
|
+
): string {
|
|
138
|
+
return new Intl.NumberFormat('en-US', {
|
|
139
|
+
style: 'currency',
|
|
140
|
+
currency,
|
|
141
|
+
}).format(value);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Format date for display
|
|
146
|
+
*/
|
|
147
|
+
export function formatDate(date: string | Date): string {
|
|
148
|
+
const d = typeof date === 'string' ? new Date(date) : date;
|
|
149
|
+
return d.toLocaleDateString('en-US', {
|
|
150
|
+
year: 'numeric',
|
|
151
|
+
month: 'short',
|
|
152
|
+
day: 'numeric',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Format datetime for display
|
|
158
|
+
*/
|
|
159
|
+
export function formatDateTime(date: string | Date): string {
|
|
160
|
+
const d = typeof date === 'string' ? new Date(date) : date;
|
|
161
|
+
return d.toLocaleString('en-US', {
|
|
162
|
+
year: 'numeric',
|
|
163
|
+
month: 'short',
|
|
164
|
+
day: 'numeric',
|
|
165
|
+
hour: '2-digit',
|
|
166
|
+
minute: '2-digit',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Format relative time (e.g., "2 hours ago")
|
|
172
|
+
*/
|
|
173
|
+
export function formatRelativeTime(date: string | Date): string {
|
|
174
|
+
const d = typeof date === 'string' ? new Date(date) : date;
|
|
175
|
+
const now = new Date();
|
|
176
|
+
const diffMs = now.getTime() - d.getTime();
|
|
177
|
+
const diffSecs = Math.floor(diffMs / 1000);
|
|
178
|
+
const diffMins = Math.floor(diffSecs / 60);
|
|
179
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
180
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
181
|
+
|
|
182
|
+
if (diffSecs < 60) return 'just now';
|
|
183
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
184
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
185
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
186
|
+
return formatDate(d);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Format file size
|
|
191
|
+
*/
|
|
192
|
+
export function formatFileSize(bytes: number): string {
|
|
193
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
194
|
+
let size = bytes;
|
|
195
|
+
let unitIndex = 0;
|
|
196
|
+
|
|
197
|
+
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
198
|
+
size /= 1024;
|
|
199
|
+
unitIndex++;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return `${size.toFixed(unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Truncate string with ellipsis
|
|
207
|
+
*/
|
|
208
|
+
export function truncate(str: string, maxLength: number): string {
|
|
209
|
+
if (str.length <= maxLength) return str;
|
|
210
|
+
return str.slice(0, maxLength - 1) + '\u2026';
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Pad string to fixed width
|
|
215
|
+
*/
|
|
216
|
+
export function padRight(str: string, width: number): string {
|
|
217
|
+
return str.padEnd(width, ' ');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Create a simple table
|
|
222
|
+
*/
|
|
223
|
+
export interface TableColumn<T> {
|
|
224
|
+
key: keyof T | string;
|
|
225
|
+
header: string;
|
|
226
|
+
width?: number;
|
|
227
|
+
format?: (value: unknown, row: T) => string;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function formatTable<T>(
|
|
231
|
+
data: T[],
|
|
232
|
+
columns: TableColumn<T>[]
|
|
233
|
+
): string {
|
|
234
|
+
if (data.length === 0) {
|
|
235
|
+
return output.dim('No results');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Calculate column widths
|
|
239
|
+
const widths = columns.map((col) => {
|
|
240
|
+
const headerWidth = col.header.length;
|
|
241
|
+
const keyStr = String(col.key);
|
|
242
|
+
const dataWidth = Math.max(
|
|
243
|
+
...data.map((row) => {
|
|
244
|
+
const value = keyStr.includes('.')
|
|
245
|
+
? getNestedValue(row as Record<string, unknown>, keyStr)
|
|
246
|
+
: (row as Record<string, unknown>)[keyStr];
|
|
247
|
+
const formatted = col.format ? col.format(value, row) : String(value ?? '');
|
|
248
|
+
return formatted.length;
|
|
249
|
+
})
|
|
250
|
+
);
|
|
251
|
+
return Math.max(headerWidth, col.width ?? dataWidth);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Build header
|
|
255
|
+
const headerRow = columns
|
|
256
|
+
.map((col, i) => output.bold(padRight(col.header, widths[i] ?? 10)))
|
|
257
|
+
.join(' ');
|
|
258
|
+
|
|
259
|
+
// Build separator
|
|
260
|
+
const separator = widths.map((w) => '\u2500'.repeat(w ?? 10)).join(' ');
|
|
261
|
+
|
|
262
|
+
// Build data rows
|
|
263
|
+
const dataRows = data.map((row) =>
|
|
264
|
+
columns
|
|
265
|
+
.map((col, i) => {
|
|
266
|
+
const keyStr = String(col.key);
|
|
267
|
+
const value = keyStr.includes('.')
|
|
268
|
+
? getNestedValue(row as Record<string, unknown>, keyStr)
|
|
269
|
+
: (row as Record<string, unknown>)[keyStr];
|
|
270
|
+
const formatted = col.format ? col.format(value, row) : String(value ?? '');
|
|
271
|
+
return padRight(formatted, widths[i] ?? 10);
|
|
272
|
+
})
|
|
273
|
+
.join(' ')
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
return [headerRow, separator, ...dataRows].join('\n');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Print a table to console
|
|
281
|
+
*/
|
|
282
|
+
export function printTable<T>(
|
|
283
|
+
data: T[],
|
|
284
|
+
columns: TableColumn<T>[]
|
|
285
|
+
): void {
|
|
286
|
+
console.log(formatTable(data, columns));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Get nested value from object using dot notation
|
|
291
|
+
*/
|
|
292
|
+
function getNestedValue(obj: Record<string, unknown>, path: string): unknown {
|
|
293
|
+
return path.split('.').reduce((acc, part) => {
|
|
294
|
+
if (acc && typeof acc === 'object') {
|
|
295
|
+
return (acc as Record<string, unknown>)[part];
|
|
296
|
+
}
|
|
297
|
+
return undefined;
|
|
298
|
+
}, obj as unknown);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Print JSON with syntax highlighting
|
|
303
|
+
*/
|
|
304
|
+
export function printJSON(data: unknown): void {
|
|
305
|
+
const json = JSON.stringify(data, null, 2);
|
|
306
|
+
// Simple syntax highlighting
|
|
307
|
+
const highlighted = json
|
|
308
|
+
.replace(/"([^"]+)":/g, output.dim('"$1":'))
|
|
309
|
+
.replace(/: "([^"]+)"/g, `: ${output.success('"$1"')}`)
|
|
310
|
+
.replace(/: (\d+)/g, `: ${output.info('$1')}`)
|
|
311
|
+
.replace(/: (true|false)/g, `: ${output.warning('$1')}`)
|
|
312
|
+
.replace(/: (null)/g, `: ${output.dim('$1')}`);
|
|
313
|
+
console.log(highlighted);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Print a divider line
|
|
318
|
+
*/
|
|
319
|
+
export function printDivider(char = '\u2500', length = 60): void {
|
|
320
|
+
console.log(output.dim(char.repeat(length)));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Print a box with content
|
|
325
|
+
*/
|
|
326
|
+
export function printBox(content: string, title?: string): void {
|
|
327
|
+
const lines = content.split('\n');
|
|
328
|
+
const maxWidth = Math.max(...lines.map((l) => l.length), title?.length ?? 0);
|
|
329
|
+
|
|
330
|
+
const top = title
|
|
331
|
+
? `\u250c\u2500 ${output.bold(title)} ${'\u2500'.repeat(maxWidth - title.length - 1)}\u2510`
|
|
332
|
+
: `\u250c${'\u2500'.repeat(maxWidth + 2)}\u2510`;
|
|
333
|
+
|
|
334
|
+
console.log(top);
|
|
335
|
+
for (const line of lines) {
|
|
336
|
+
console.log(`\u2502 ${padRight(line, maxWidth)} \u2502`);
|
|
337
|
+
}
|
|
338
|
+
console.log(`\u2514${'\u2500'.repeat(maxWidth + 2)}\u2518`);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Status badge formatter
|
|
343
|
+
*/
|
|
344
|
+
export function formatStatus(status: string): string {
|
|
345
|
+
const statusColors: Record<string, keyof typeof colors> = {
|
|
346
|
+
// Contact status
|
|
347
|
+
lead: 'cyan',
|
|
348
|
+
prospect: 'blue',
|
|
349
|
+
qualified: 'yellow',
|
|
350
|
+
customer: 'green',
|
|
351
|
+
churned: 'red',
|
|
352
|
+
archived: 'dim',
|
|
353
|
+
|
|
354
|
+
// Deal stages
|
|
355
|
+
prospecting: 'cyan',
|
|
356
|
+
qualification: 'blue',
|
|
357
|
+
needs_analysis: 'yellow',
|
|
358
|
+
proposal: 'magenta',
|
|
359
|
+
negotiation: 'yellow',
|
|
360
|
+
closed_won: 'green',
|
|
361
|
+
closed_lost: 'red',
|
|
362
|
+
|
|
363
|
+
// Activity types
|
|
364
|
+
call: 'cyan',
|
|
365
|
+
email: 'blue',
|
|
366
|
+
meeting: 'magenta',
|
|
367
|
+
task: 'yellow',
|
|
368
|
+
note: 'dim',
|
|
369
|
+
|
|
370
|
+
// Priority
|
|
371
|
+
low: 'dim',
|
|
372
|
+
medium: 'yellow',
|
|
373
|
+
high: 'red',
|
|
374
|
+
urgent: 'bgRed',
|
|
375
|
+
|
|
376
|
+
// General
|
|
377
|
+
active: 'green',
|
|
378
|
+
inactive: 'dim',
|
|
379
|
+
pending: 'yellow',
|
|
380
|
+
completed: 'green',
|
|
381
|
+
cancelled: 'red',
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
const color = statusColors[status.toLowerCase()] || 'white';
|
|
385
|
+
return colorize(`[${status.toUpperCase()}]`, color);
|
|
386
|
+
}
|