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.
Files changed (45) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/LICENSE +21 -0
  3. package/README.md +318 -0
  4. package/data/orchestrator.json +113 -0
  5. package/package.json +49 -0
  6. package/src/auth/recovery.mjs +328 -0
  7. package/src/auth/refresh.mjs +373 -0
  8. package/src/chef.mjs +348 -0
  9. package/src/cli/doctor.mjs +568 -0
  10. package/src/cli/reset.mjs +447 -0
  11. package/src/cli/status.mjs +379 -0
  12. package/src/cli.mjs +429 -0
  13. package/src/commands/doctor.mjs +375 -0
  14. package/src/commands/help.mjs +324 -0
  15. package/src/commands/status.mjs +331 -0
  16. package/src/monitor/health.mjs +486 -0
  17. package/src/monitor/performance.mjs +442 -0
  18. package/src/monitor/report.mjs +535 -0
  19. package/src/orchestrator/classify.mjs +391 -0
  20. package/src/orchestrator/confidence.mjs +151 -0
  21. package/src/orchestrator/handoffs.mjs +231 -0
  22. package/src/orchestrator/review.mjs +222 -0
  23. package/src/providers/balance.mjs +201 -0
  24. package/src/providers/claude.mjs +236 -0
  25. package/src/providers/codex.mjs +255 -0
  26. package/src/providers/detect.mjs +185 -0
  27. package/src/providers/errors.mjs +373 -0
  28. package/src/providers/select.mjs +162 -0
  29. package/src/repl-enhanced.mjs +417 -0
  30. package/src/repl.mjs +321 -0
  31. package/src/state/archive.mjs +366 -0
  32. package/src/state/atomic.mjs +116 -0
  33. package/src/state/cleanup.mjs +440 -0
  34. package/src/state/recovery.mjs +461 -0
  35. package/src/state/session.mjs +147 -0
  36. package/src/ui/errors.mjs +456 -0
  37. package/src/ui/formatter.mjs +327 -0
  38. package/src/ui/icons.mjs +318 -0
  39. package/src/ui/progress.mjs +468 -0
  40. package/templates/prompts/confidence-format.txt +14 -0
  41. package/templates/prompts/ic-with-feedback.txt +41 -0
  42. package/templates/prompts/ic.txt +13 -0
  43. package/templates/prompts/manager-review.txt +40 -0
  44. package/templates/prompts/manager.txt +14 -0
  45. 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
+ }
@@ -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
+ }