myshell-tools 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +69 -0
- package/LICENSE +21 -0
- package/README.md +318 -0
- package/data/orchestrator.json +113 -0
- package/package.json +49 -0
- package/src/auth/recovery.mjs +328 -0
- package/src/auth/refresh.mjs +373 -0
- package/src/chef.mjs +348 -0
- package/src/cli/doctor.mjs +568 -0
- package/src/cli/reset.mjs +447 -0
- package/src/cli/status.mjs +379 -0
- package/src/cli.mjs +429 -0
- package/src/commands/doctor.mjs +375 -0
- package/src/commands/help.mjs +324 -0
- package/src/commands/status.mjs +331 -0
- package/src/monitor/health.mjs +486 -0
- package/src/monitor/performance.mjs +442 -0
- package/src/monitor/report.mjs +535 -0
- package/src/orchestrator/classify.mjs +391 -0
- package/src/orchestrator/confidence.mjs +151 -0
- package/src/orchestrator/handoffs.mjs +231 -0
- package/src/orchestrator/review.mjs +222 -0
- package/src/providers/balance.mjs +201 -0
- package/src/providers/claude.mjs +236 -0
- package/src/providers/codex.mjs +255 -0
- package/src/providers/detect.mjs +185 -0
- package/src/providers/errors.mjs +373 -0
- package/src/providers/select.mjs +162 -0
- package/src/repl-enhanced.mjs +417 -0
- package/src/repl.mjs +321 -0
- package/src/state/archive.mjs +366 -0
- package/src/state/atomic.mjs +116 -0
- package/src/state/cleanup.mjs +440 -0
- package/src/state/recovery.mjs +461 -0
- package/src/state/session.mjs +147 -0
- package/src/ui/errors.mjs +456 -0
- package/src/ui/formatter.mjs +327 -0
- package/src/ui/icons.mjs +318 -0
- package/src/ui/progress.mjs +468 -0
- package/templates/prompts/confidence-format.txt +14 -0
- package/templates/prompts/ic-with-feedback.txt +41 -0
- package/templates/prompts/ic.txt +13 -0
- package/templates/prompts/manager-review.txt +40 -0
- package/templates/prompts/manager.txt +14 -0
- package/templates/prompts/worker.txt +12 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* formatter.mjs — Rich terminal output formatting utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Colors and formatting
|
|
7
|
+
*/
|
|
8
|
+
export const colors = {
|
|
9
|
+
// Basic colors
|
|
10
|
+
red: '\x1b[31m',
|
|
11
|
+
green: '\x1b[32m',
|
|
12
|
+
yellow: '\x1b[33m',
|
|
13
|
+
blue: '\x1b[34m',
|
|
14
|
+
magenta: '\x1b[35m',
|
|
15
|
+
cyan: '\x1b[36m',
|
|
16
|
+
white: '\x1b[37m',
|
|
17
|
+
|
|
18
|
+
// Extended colors
|
|
19
|
+
orange: '\x1b[38;5;208m',
|
|
20
|
+
brightBlue: '\x1b[38;5;33m',
|
|
21
|
+
brightGreen: '\x1b[38;5;40m',
|
|
22
|
+
purple: '\x1b[38;5;135m',
|
|
23
|
+
|
|
24
|
+
// Formatting
|
|
25
|
+
reset: '\x1b[0m',
|
|
26
|
+
bold: '\x1b[1m',
|
|
27
|
+
dim: '\x1b[2m',
|
|
28
|
+
italic: '\x1b[3m',
|
|
29
|
+
underline: '\x1b[4m',
|
|
30
|
+
|
|
31
|
+
// Background colors
|
|
32
|
+
bgRed: '\x1b[41m',
|
|
33
|
+
bgGreen: '\x1b[42m',
|
|
34
|
+
bgYellow: '\x1b[43m',
|
|
35
|
+
bgBlue: '\x1b[44m',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Helper functions for color formatting
|
|
40
|
+
*/
|
|
41
|
+
export const fmt = {
|
|
42
|
+
red: (text) => `${colors.red}${text}${colors.reset}`,
|
|
43
|
+
green: (text) => `${colors.green}${text}${colors.reset}`,
|
|
44
|
+
yellow: (text) => `${colors.yellow}${text}${colors.reset}`,
|
|
45
|
+
blue: (text) => `${colors.blue}${text}${colors.reset}`,
|
|
46
|
+
magenta: (text) => `${colors.magenta}${text}${colors.reset}`,
|
|
47
|
+
cyan: (text) => `${colors.cyan}${text}${colors.reset}`,
|
|
48
|
+
orange: (text) => `${colors.orange}${text}${colors.reset}`,
|
|
49
|
+
brightBlue: (text) => `${colors.brightBlue}${text}${colors.reset}`,
|
|
50
|
+
brightGreen: (text) => `${colors.brightGreen}${text}${colors.reset}`,
|
|
51
|
+
purple: (text) => `${colors.purple}${text}${colors.reset}`,
|
|
52
|
+
|
|
53
|
+
bold: (text) => `${colors.bold}${text}${colors.reset}`,
|
|
54
|
+
dim: (text) => `${colors.dim}${text}${colors.reset}`,
|
|
55
|
+
italic: (text) => `${colors.italic}${text}${colors.reset}`,
|
|
56
|
+
underline: (text) => `${colors.underline}${text}${colors.reset}`,
|
|
57
|
+
|
|
58
|
+
success: (text) => `${colors.bold}${colors.green}${text}${colors.reset}`,
|
|
59
|
+
error: (text) => `${colors.bold}${colors.red}${text}${colors.reset}`,
|
|
60
|
+
warning: (text) => `${colors.bold}${colors.yellow}${text}${colors.reset}`,
|
|
61
|
+
info: (text) => `${colors.bold}${colors.blue}${text}${colors.reset}`,
|
|
62
|
+
|
|
63
|
+
// Combinations
|
|
64
|
+
redBold: (text) => `${colors.bold}${colors.red}${text}${colors.reset}`,
|
|
65
|
+
greenBold: (text) => `${colors.bold}${colors.green}${text}${colors.reset}`,
|
|
66
|
+
yellowBold: (text) => `${colors.bold}${colors.yellow}${text}${colors.reset}`,
|
|
67
|
+
blueBold: (text) => `${colors.bold}${colors.blue}${text}${colors.reset}`,
|
|
68
|
+
orangeBold: (text) => `${colors.bold}${colors.orange}${text}${colors.reset}`,
|
|
69
|
+
|
|
70
|
+
// Add formatModel to fmt object for easier access
|
|
71
|
+
formatModel: formatModel,
|
|
72
|
+
// Add providerBalanceBar to fmt object
|
|
73
|
+
providerBalanceBar: providerBalanceBar
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Tier color mapping for consistent hierarchy display
|
|
78
|
+
*/
|
|
79
|
+
export const tierColors = {
|
|
80
|
+
worker: colors.blue,
|
|
81
|
+
ic: colors.yellow,
|
|
82
|
+
manager: colors.red,
|
|
83
|
+
system: colors.cyan
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Format tier name with appropriate color
|
|
88
|
+
*/
|
|
89
|
+
export function formatTier(tier) {
|
|
90
|
+
const color = tierColors[tier] || colors.white;
|
|
91
|
+
return `${color}${colors.bold}${tier.toUpperCase()}${colors.reset}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Create a visual tree structure
|
|
96
|
+
*/
|
|
97
|
+
export function createTree(items, options = {}) {
|
|
98
|
+
const { indent = ' ', branch = '├─', lastBranch = '└─', continuation = '│ ' } = options;
|
|
99
|
+
const lines = [];
|
|
100
|
+
|
|
101
|
+
for (let i = 0; i < items.length; i++) {
|
|
102
|
+
const item = items[i];
|
|
103
|
+
const isLast = i === items.length - 1;
|
|
104
|
+
const prefix = isLast ? lastBranch : branch;
|
|
105
|
+
|
|
106
|
+
if (typeof item === 'string') {
|
|
107
|
+
lines.push(`${indent}${prefix} ${item}`);
|
|
108
|
+
} else if (item.text) {
|
|
109
|
+
lines.push(`${indent}${prefix} ${item.text}`);
|
|
110
|
+
if (item.children && item.children.length > 0) {
|
|
111
|
+
const childLines = createTree(item.children, {
|
|
112
|
+
...options,
|
|
113
|
+
indent: indent + (isLast ? ' ' : continuation)
|
|
114
|
+
});
|
|
115
|
+
lines.push(...childLines);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return lines;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Format duration in human-readable format
|
|
125
|
+
*/
|
|
126
|
+
export function formatDuration(milliseconds) {
|
|
127
|
+
if (milliseconds < 1000) {
|
|
128
|
+
return `${milliseconds}ms`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const seconds = milliseconds / 1000;
|
|
132
|
+
if (seconds < 60) {
|
|
133
|
+
return `${seconds.toFixed(1)}s`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const minutes = seconds / 60;
|
|
137
|
+
if (minutes < 60) {
|
|
138
|
+
return `${minutes.toFixed(1)}m`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const hours = minutes / 60;
|
|
142
|
+
return `${hours.toFixed(1)}h`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Format confidence level with color coding
|
|
147
|
+
*/
|
|
148
|
+
export function formatConfidence(confidence) {
|
|
149
|
+
const percent = Math.round(confidence * 100);
|
|
150
|
+
|
|
151
|
+
if (confidence >= 0.8) {
|
|
152
|
+
return `${colors.green}${percent}%${colors.reset}`;
|
|
153
|
+
} else if (confidence >= 0.6) {
|
|
154
|
+
return `${colors.yellow}${percent}%${colors.reset}`;
|
|
155
|
+
} else {
|
|
156
|
+
return `${colors.red}${percent}%${colors.reset}`;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Create a horizontal separator line
|
|
162
|
+
*/
|
|
163
|
+
export function separator(length = 60, char = '═', color = colors.blue) {
|
|
164
|
+
return `${color}${char.repeat(length)}${colors.reset}`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Create a bordered box around text
|
|
169
|
+
*/
|
|
170
|
+
export function box(text, options = {}) {
|
|
171
|
+
const {
|
|
172
|
+
padding = 1,
|
|
173
|
+
margin = 0,
|
|
174
|
+
borderColor = colors.blue,
|
|
175
|
+
textColor = colors.reset,
|
|
176
|
+
width = null
|
|
177
|
+
} = options;
|
|
178
|
+
|
|
179
|
+
const lines = text.split('\n');
|
|
180
|
+
const maxLineLength = width || Math.max(...lines.map(line => line.length));
|
|
181
|
+
const totalWidth = maxLineLength + (padding * 2);
|
|
182
|
+
|
|
183
|
+
const topBorder = `${borderColor}╭${'─'.repeat(totalWidth)}╮${colors.reset}`;
|
|
184
|
+
const bottomBorder = `${borderColor}╰${'─'.repeat(totalWidth)}╯${colors.reset}`;
|
|
185
|
+
|
|
186
|
+
const result = [];
|
|
187
|
+
|
|
188
|
+
// Add margin above
|
|
189
|
+
for (let i = 0; i < margin; i++) {
|
|
190
|
+
result.push('');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
result.push(topBorder);
|
|
194
|
+
|
|
195
|
+
for (const line of lines) {
|
|
196
|
+
const paddedLine = line.padEnd(maxLineLength);
|
|
197
|
+
result.push(`${borderColor}│${' '.repeat(padding)}${textColor}${paddedLine}${' '.repeat(padding)}${borderColor}│${colors.reset}`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
result.push(bottomBorder);
|
|
201
|
+
|
|
202
|
+
// Add margin below
|
|
203
|
+
for (let i = 0; i < margin; i++) {
|
|
204
|
+
result.push('');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return result.join('\n');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Format a progress bar
|
|
212
|
+
*/
|
|
213
|
+
export function progressBar(current, total, options = {}) {
|
|
214
|
+
const {
|
|
215
|
+
width = 20,
|
|
216
|
+
filled = '█',
|
|
217
|
+
empty = '░',
|
|
218
|
+
showPercent = true,
|
|
219
|
+
color = colors.green
|
|
220
|
+
} = options;
|
|
221
|
+
|
|
222
|
+
const progress = Math.min(current / total, 1);
|
|
223
|
+
const filledWidth = Math.round(progress * width);
|
|
224
|
+
const emptyWidth = width - filledWidth;
|
|
225
|
+
|
|
226
|
+
const bar = `${color}${filled.repeat(filledWidth)}${colors.dim}${empty.repeat(emptyWidth)}${colors.reset}`;
|
|
227
|
+
|
|
228
|
+
if (showPercent) {
|
|
229
|
+
const percent = Math.round(progress * 100);
|
|
230
|
+
return `${bar} ${percent}%`;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return bar;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Format provider balance bar (like dual-brain)
|
|
238
|
+
*/
|
|
239
|
+
export function providerBalanceBar(claudePercent, openaiPercent, options = {}) {
|
|
240
|
+
const { width = 20, label = true } = options;
|
|
241
|
+
|
|
242
|
+
if (claudePercent === 0 && openaiPercent === 0) {
|
|
243
|
+
const bar = fmt.dim('░'.repeat(width));
|
|
244
|
+
return label ? `${bar} no activity` : bar;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const claudeFill = Math.round((claudePercent / 100) * width);
|
|
248
|
+
const openaieFill = width - claudeFill;
|
|
249
|
+
|
|
250
|
+
const claudeBar = fmt.orange('█'.repeat(claudeFill));
|
|
251
|
+
const openaiBar = fmt.green('▓'.repeat(openaieFill));
|
|
252
|
+
|
|
253
|
+
const bar = `${claudeBar}${openaiBar}`;
|
|
254
|
+
|
|
255
|
+
if (label) {
|
|
256
|
+
return `${bar} ${fmt.orange(claudePercent + '%')} Claude · ${fmt.green(openaiPercent + '%')} GPT`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return bar;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Format time ago (like dual-brain)
|
|
264
|
+
*/
|
|
265
|
+
export function timeAgo(timestamp) {
|
|
266
|
+
const now = Date.now();
|
|
267
|
+
const diff = now - timestamp;
|
|
268
|
+
const minutes = Math.floor(diff / 60000);
|
|
269
|
+
|
|
270
|
+
if (minutes < 1) return 'just now';
|
|
271
|
+
if (minutes < 60) return `${minutes}m ago`;
|
|
272
|
+
|
|
273
|
+
const hours = Math.floor(minutes / 60);
|
|
274
|
+
if (hours < 24) return `${hours}h ago`;
|
|
275
|
+
|
|
276
|
+
const days = Math.floor(hours / 24);
|
|
277
|
+
return `${days}d ago`;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Truncate text with ellipsis
|
|
282
|
+
*/
|
|
283
|
+
export function truncate(text, maxLength = 50) {
|
|
284
|
+
if (!text) return '';
|
|
285
|
+
const cleaned = text.replace(/\s+/g, ' ').trim();
|
|
286
|
+
if (cleaned.length <= maxLength) return cleaned;
|
|
287
|
+
return cleaned.slice(0, maxLength - 1) + '…';
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Format model name consistently
|
|
292
|
+
*/
|
|
293
|
+
export function formatModel(provider, model) {
|
|
294
|
+
if (provider === 'claude') {
|
|
295
|
+
return fmt.orange(`${provider}/${model}`);
|
|
296
|
+
} else if (provider === 'openai' || provider === 'codex') {
|
|
297
|
+
return fmt.green(`GPT/${model}`);
|
|
298
|
+
}
|
|
299
|
+
return fmt.dim(`${provider}/${model}`);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Create a status indicator
|
|
304
|
+
*/
|
|
305
|
+
export function statusIndicator(status) {
|
|
306
|
+
switch (status) {
|
|
307
|
+
case 'success':
|
|
308
|
+
case 'ready':
|
|
309
|
+
case 'active':
|
|
310
|
+
return fmt.green('✅');
|
|
311
|
+
case 'warning':
|
|
312
|
+
case 'partial':
|
|
313
|
+
return fmt.yellow('⚠️');
|
|
314
|
+
case 'error':
|
|
315
|
+
case 'failed':
|
|
316
|
+
return fmt.red('❌');
|
|
317
|
+
case 'loading':
|
|
318
|
+
case 'processing':
|
|
319
|
+
return fmt.blue('🔄');
|
|
320
|
+
case 'info':
|
|
321
|
+
return fmt.blue('💡');
|
|
322
|
+
case 'docs':
|
|
323
|
+
return fmt.blue('📖');
|
|
324
|
+
default:
|
|
325
|
+
return fmt.dim('●');
|
|
326
|
+
}
|
|
327
|
+
}
|
package/src/ui/icons.mjs
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* icons.mjs — Unicode symbols and visual indicators
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Status icons
|
|
7
|
+
*/
|
|
8
|
+
export const status = {
|
|
9
|
+
success: '✅',
|
|
10
|
+
error: '❌',
|
|
11
|
+
warning: '⚠️',
|
|
12
|
+
info: '💡',
|
|
13
|
+
loading: '🔄',
|
|
14
|
+
docs: '📖',
|
|
15
|
+
checkmark: '✓',
|
|
16
|
+
cross: '✗',
|
|
17
|
+
bullet: '●',
|
|
18
|
+
diamond: '◆',
|
|
19
|
+
triangle: '▲',
|
|
20
|
+
square: '■',
|
|
21
|
+
circle: '○',
|
|
22
|
+
star: '★',
|
|
23
|
+
heart: '♥',
|
|
24
|
+
brain: '🧠',
|
|
25
|
+
robot: '🤖',
|
|
26
|
+
gear: '⚙️',
|
|
27
|
+
rocket: '🚀',
|
|
28
|
+
fire: '🔥',
|
|
29
|
+
lightning: '⚡',
|
|
30
|
+
shield: '🛡️',
|
|
31
|
+
crown: '👑',
|
|
32
|
+
crystal: '💎',
|
|
33
|
+
target: '🎯'
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Provider and model icons
|
|
38
|
+
*/
|
|
39
|
+
export const provider = {
|
|
40
|
+
claude: '🟠',
|
|
41
|
+
openai: '🟢',
|
|
42
|
+
codex: '🟢',
|
|
43
|
+
anthropic: '🟠',
|
|
44
|
+
gpt: '🟢'
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Tier/role icons
|
|
49
|
+
*/
|
|
50
|
+
export const tier = {
|
|
51
|
+
manager: '👔',
|
|
52
|
+
ic: '👨💻',
|
|
53
|
+
worker: '🏗️',
|
|
54
|
+
search: '🔍',
|
|
55
|
+
execute: '⚡',
|
|
56
|
+
think: '🧠',
|
|
57
|
+
review: '👀',
|
|
58
|
+
architect: '🏛️',
|
|
59
|
+
debug: '🐛',
|
|
60
|
+
test: '🧪',
|
|
61
|
+
deploy: '🚀',
|
|
62
|
+
security: '🔒',
|
|
63
|
+
docs: '📝'
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Progress and activity icons
|
|
68
|
+
*/
|
|
69
|
+
export const progress = {
|
|
70
|
+
spinner: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
|
|
71
|
+
dots: ['⠁', '⠂', '⠄', '⡀', '⢀', '⠠', '⠐', '⠈'],
|
|
72
|
+
blocks: ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'],
|
|
73
|
+
arrow: ['←', '↖', '↑', '↗', '→', '↘', '↓', '↙'],
|
|
74
|
+
clock: ['🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚', '🕛']
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Tree structure characters
|
|
79
|
+
*/
|
|
80
|
+
export const tree = {
|
|
81
|
+
branch: '├─',
|
|
82
|
+
lastBranch: '└─',
|
|
83
|
+
pipe: '│',
|
|
84
|
+
space: ' ',
|
|
85
|
+
tee: '├',
|
|
86
|
+
corner: '└',
|
|
87
|
+
horizontal: '─',
|
|
88
|
+
vertical: '│'
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Box drawing characters
|
|
93
|
+
*/
|
|
94
|
+
export const box = {
|
|
95
|
+
// Single line
|
|
96
|
+
topLeft: '╭',
|
|
97
|
+
topRight: '╮',
|
|
98
|
+
bottomLeft: '╰',
|
|
99
|
+
bottomRight: '╯',
|
|
100
|
+
horizontal: '─',
|
|
101
|
+
vertical: '│',
|
|
102
|
+
|
|
103
|
+
// Double line
|
|
104
|
+
doubleTopLeft: '╔',
|
|
105
|
+
doubleTopRight: '╗',
|
|
106
|
+
doubleBottomLeft: '╚',
|
|
107
|
+
doubleBottomRight: '╝',
|
|
108
|
+
doubleHorizontal: '═',
|
|
109
|
+
doubleVertical: '║',
|
|
110
|
+
|
|
111
|
+
// Heavy line
|
|
112
|
+
heavyTopLeft: '┏',
|
|
113
|
+
heavyTopRight: '┓',
|
|
114
|
+
heavyBottomLeft: '┗',
|
|
115
|
+
heavyBottomRight: '┛',
|
|
116
|
+
heavyHorizontal: '━',
|
|
117
|
+
heavyVertical: '┃'
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Progress bar characters
|
|
122
|
+
*/
|
|
123
|
+
export const progressChars = {
|
|
124
|
+
filled: '█',
|
|
125
|
+
empty: '░',
|
|
126
|
+
partial: ['▏', '▎', '▍', '▌', '▋', '▊', '▉'],
|
|
127
|
+
blocks: ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'],
|
|
128
|
+
dots: '⣿',
|
|
129
|
+
emptyDots: '⣀'
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Confidence level icons
|
|
134
|
+
*/
|
|
135
|
+
export const confidence = {
|
|
136
|
+
high: '🟢', // >= 80%
|
|
137
|
+
medium: '🟡', // 60-79%
|
|
138
|
+
low: '🟠', // 40-59%
|
|
139
|
+
veryLow: '🔴' // < 40%
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get confidence icon based on numeric value
|
|
144
|
+
*/
|
|
145
|
+
export function getConfidenceIcon(value) {
|
|
146
|
+
if (value >= 0.8) return confidence.high;
|
|
147
|
+
if (value >= 0.6) return confidence.medium;
|
|
148
|
+
if (value >= 0.4) return confidence.low;
|
|
149
|
+
return confidence.veryLow;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Model-specific icons
|
|
154
|
+
*/
|
|
155
|
+
export const models = {
|
|
156
|
+
// Claude models
|
|
157
|
+
opus: '👔', // Manager tier
|
|
158
|
+
sonnet: '👨💻', // IC tier
|
|
159
|
+
haiku: '🏗️', // Worker tier
|
|
160
|
+
|
|
161
|
+
// GPT models
|
|
162
|
+
'gpt-5.5': '👔',
|
|
163
|
+
'gpt-5.4': '👨💻',
|
|
164
|
+
'gpt-4.1-mini': '🏗️',
|
|
165
|
+
'gpt-4.1': '👨💻',
|
|
166
|
+
'gpt-4': '👨💻',
|
|
167
|
+
'gpt-3.5': '🏗️'
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Get model icon by name
|
|
172
|
+
*/
|
|
173
|
+
export function getModelIcon(modelName) {
|
|
174
|
+
if (!modelName) return tier.worker;
|
|
175
|
+
|
|
176
|
+
const name = modelName.toLowerCase();
|
|
177
|
+
|
|
178
|
+
// Check exact matches first
|
|
179
|
+
if (models[name]) return models[name];
|
|
180
|
+
|
|
181
|
+
// Check partial matches
|
|
182
|
+
if (name.includes('opus')) return models.opus;
|
|
183
|
+
if (name.includes('sonnet')) return models.sonnet;
|
|
184
|
+
if (name.includes('haiku')) return models.haiku;
|
|
185
|
+
if (name.includes('gpt-5.5')) return models['gpt-5.5'];
|
|
186
|
+
if (name.includes('gpt-5.4')) return models['gpt-5.4'];
|
|
187
|
+
if (name.includes('gpt-4.1-mini') || name.includes('mini')) return models['gpt-4.1-mini'];
|
|
188
|
+
if (name.includes('gpt-4.1')) return models['gpt-4.1'];
|
|
189
|
+
if (name.includes('gpt-4')) return models['gpt-4'];
|
|
190
|
+
if (name.includes('gpt-3.5')) return models['gpt-3.5'];
|
|
191
|
+
|
|
192
|
+
// Default fallback
|
|
193
|
+
return tier.worker;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Activity/action icons
|
|
198
|
+
*/
|
|
199
|
+
export const actions = {
|
|
200
|
+
start: '▶️',
|
|
201
|
+
stop: '⏹️',
|
|
202
|
+
pause: '⏸️',
|
|
203
|
+
restart: '🔄',
|
|
204
|
+
create: '➕',
|
|
205
|
+
delete: '🗑️',
|
|
206
|
+
edit: '✏️',
|
|
207
|
+
save: '💾',
|
|
208
|
+
load: '📂',
|
|
209
|
+
upload: '⬆️',
|
|
210
|
+
download: '⬇️',
|
|
211
|
+
sync: '🔄',
|
|
212
|
+
backup: '💾',
|
|
213
|
+
restore: '🔄',
|
|
214
|
+
configure: '⚙️',
|
|
215
|
+
install: '📦',
|
|
216
|
+
uninstall: '🗑️',
|
|
217
|
+
upgrade: '⬆️',
|
|
218
|
+
downgrade: '⬇️',
|
|
219
|
+
reset: '🔄',
|
|
220
|
+
clear: '🧹',
|
|
221
|
+
search: '🔍',
|
|
222
|
+
filter: '🔎',
|
|
223
|
+
sort: '📊',
|
|
224
|
+
export: '📤',
|
|
225
|
+
import: '📥',
|
|
226
|
+
copy: '📋',
|
|
227
|
+
cut: '✂️',
|
|
228
|
+
paste: '📋',
|
|
229
|
+
undo: '↶',
|
|
230
|
+
redo: '↷'
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Session state icons
|
|
235
|
+
*/
|
|
236
|
+
export const session = {
|
|
237
|
+
new: '🆕',
|
|
238
|
+
active: '🟢',
|
|
239
|
+
paused: '⏸️',
|
|
240
|
+
completed: '✅',
|
|
241
|
+
failed: '❌',
|
|
242
|
+
interrupted: '⚠️',
|
|
243
|
+
archived: '📦',
|
|
244
|
+
deleted: '🗑️'
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* File operation icons
|
|
249
|
+
*/
|
|
250
|
+
export const files = {
|
|
251
|
+
read: '📖',
|
|
252
|
+
write: '✏️',
|
|
253
|
+
create: '➕',
|
|
254
|
+
delete: '🗑️',
|
|
255
|
+
move: '📦',
|
|
256
|
+
copy: '📋',
|
|
257
|
+
folder: '📁',
|
|
258
|
+
file: '📄',
|
|
259
|
+
code: '💻',
|
|
260
|
+
config: '⚙️',
|
|
261
|
+
data: '📊',
|
|
262
|
+
image: '🖼️',
|
|
263
|
+
document: '📝',
|
|
264
|
+
archive: '📦',
|
|
265
|
+
lock: '🔒',
|
|
266
|
+
unlock: '🔓'
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* System health icons
|
|
271
|
+
*/
|
|
272
|
+
export const health = {
|
|
273
|
+
healthy: '💚',
|
|
274
|
+
warning: '💛',
|
|
275
|
+
critical: '❤️',
|
|
276
|
+
unknown: '🤍',
|
|
277
|
+
offline: '💔',
|
|
278
|
+
maintenance: '🔧',
|
|
279
|
+
degraded: '⚠️'
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Networking icons
|
|
284
|
+
*/
|
|
285
|
+
export const network = {
|
|
286
|
+
connected: '🌐',
|
|
287
|
+
disconnected: '📡',
|
|
288
|
+
uploading: '⬆️',
|
|
289
|
+
downloading: '⬇️',
|
|
290
|
+
syncing: '🔄',
|
|
291
|
+
error: '💥',
|
|
292
|
+
timeout: '⏰',
|
|
293
|
+
retry: '🔄'
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Get a random spinner frame
|
|
298
|
+
*/
|
|
299
|
+
export function getSpinnerFrame(index) {
|
|
300
|
+
return progress.spinner[index % progress.spinner.length];
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Create a simple spinner animation
|
|
305
|
+
*/
|
|
306
|
+
export function createSpinner() {
|
|
307
|
+
let frame = 0;
|
|
308
|
+
return {
|
|
309
|
+
tick() {
|
|
310
|
+
const icon = getSpinnerFrame(frame);
|
|
311
|
+
frame++;
|
|
312
|
+
return icon;
|
|
313
|
+
},
|
|
314
|
+
stop() {
|
|
315
|
+
frame = 0;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
}
|