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,442 @@
1
+ /**
2
+ * performance.mjs — Performance tracking and efficiency monitoring
3
+ */
4
+
5
+ import { existsSync, mkdirSync } from 'fs';
6
+ import { join } from 'path';
7
+ import { atomicAppendJSONL, atomicWriteJSON, lockedReadModifyWrite } from '../state/atomic.mjs';
8
+
9
+ /**
10
+ * Performance baselines for comparison
11
+ */
12
+ const BASELINES = {
13
+ // Estimated baseline costs for dual-verification vs. hierarchy
14
+ dualVerificationMultiplier: 2.5, // Dual-verification uses 2.5x more tokens
15
+ averageEscalationRate: 0.25, // 25% of tasks escalate
16
+ targetConfidence: 0.75, // Target average confidence
17
+ maxHandoffTime: 3000, // Maximum acceptable handoff time (ms)
18
+
19
+ // Token usage baselines (rough estimates)
20
+ tokenCosts: {
21
+ worker: { input: 0.25, output: 1.25 }, // per 1K tokens (USD)
22
+ ic: { input: 3.0, output: 15.0 },
23
+ manager: { input: 15.0, output: 75.0 }
24
+ }
25
+ };
26
+
27
+ /**
28
+ * Get performance metrics directory
29
+ */
30
+ function getMetricsDir(workspace = process.cwd()) {
31
+ const metricsDir = join(workspace, '.cortex', 'metrics');
32
+ if (!existsSync(metricsDir)) {
33
+ mkdirSync(metricsDir, { recursive: true });
34
+ }
35
+ return metricsDir;
36
+ }
37
+
38
+ /**
39
+ * Performance monitoring class
40
+ */
41
+ export class PerformanceMonitor {
42
+ constructor(workspace = process.cwd()) {
43
+ this.workspace = workspace;
44
+ this.metricsDir = getMetricsDir(workspace);
45
+ this.currentSession = {
46
+ startTime: Date.now(),
47
+ handoffs: [],
48
+ escalations: 0,
49
+ totalTokensUsed: 0,
50
+ totalCostUSD: 0,
51
+ taskCount: 0
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Track a handoff operation
57
+ */
58
+ trackHandoff(handoff) {
59
+ const handoffData = {
60
+ timestamp: Date.now(),
61
+ operation: handoff.operation, // 'execute', 'escalate', 'delegate', 'review'
62
+ fromTier: handoff.fromTier,
63
+ toTier: handoff.toTier,
64
+ provider: handoff.provider,
65
+ model: handoff.model,
66
+ confidence: handoff.confidence,
67
+ success: handoff.success,
68
+ durationMs: handoff.durationMs,
69
+ tokensUsed: handoff.tokensUsed || this.estimateTokens(handoff),
70
+ costUSD: handoff.costUSD || this.calculateCost(handoff),
71
+ sessionId: this.currentSession.startTime
72
+ };
73
+
74
+ this.currentSession.handoffs.push(handoffData);
75
+ this.currentSession.totalTokensUsed += handoffData.tokensUsed;
76
+ this.currentSession.totalCostUSD += handoffData.costUSD;
77
+
78
+ if (handoff.operation === 'escalate') {
79
+ this.currentSession.escalations++;
80
+ }
81
+
82
+ if (handoff.operation === 'execute') {
83
+ this.currentSession.taskCount++;
84
+ }
85
+
86
+ // Append to persistent log
87
+ const logPath = join(this.metricsDir, 'handoffs.jsonl');
88
+ atomicAppendJSONL(logPath, handoffData);
89
+
90
+ return handoffData;
91
+ }
92
+
93
+ /**
94
+ * Estimate token usage for a handoff
95
+ */
96
+ estimateTokens(handoff) {
97
+ const promptLength = handoff.prompt?.length || 1000;
98
+ const outputLength = handoff.output?.length || 500;
99
+
100
+ // Rough estimation: 4 characters per token
101
+ const inputTokens = Math.ceil(promptLength / 4);
102
+ const outputTokens = Math.ceil(outputLength / 4);
103
+
104
+ return {
105
+ input: inputTokens,
106
+ output: outputTokens,
107
+ total: inputTokens + outputTokens
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Calculate cost based on tier and tokens
113
+ */
114
+ calculateCost(handoff) {
115
+ const tier = handoff.toTier || handoff.tier;
116
+ const tokens = handoff.tokensUsed || this.estimateTokens(handoff);
117
+ const rates = BASELINES.tokenCosts[tier] || BASELINES.tokenCosts.ic;
118
+
119
+ const inputCost = (tokens.input / 1000) * rates.input / 100; // Convert to USD
120
+ const outputCost = (tokens.output / 1000) * rates.output / 100;
121
+
122
+ return inputCost + outputCost;
123
+ }
124
+
125
+ /**
126
+ * Calculate efficiency vs baseline
127
+ */
128
+ calculateEfficiencyVsBaseline() {
129
+ const totalTasks = this.currentSession.taskCount;
130
+ if (totalTasks === 0) return null;
131
+
132
+ // Estimated cost if using dual-verification for all tasks
133
+ const baselineCost = this.currentSession.totalCostUSD * BASELINES.dualVerificationMultiplier;
134
+ const actualCost = this.currentSession.totalCostUSD;
135
+
136
+ const efficiency = {
137
+ tokenSavings: 1 - (actualCost / baselineCost),
138
+ costSavingsUSD: baselineCost - actualCost,
139
+ escalationRate: this.currentSession.escalations / totalTasks,
140
+ averageConfidence: this.calculateAverageConfidence()
141
+ };
142
+
143
+ return efficiency;
144
+ }
145
+
146
+ /**
147
+ * Calculate average confidence across successful operations
148
+ */
149
+ calculateAverageConfidence() {
150
+ const successfulHandoffs = this.currentSession.handoffs.filter(h =>
151
+ h.success && h.confidence !== null
152
+ );
153
+
154
+ if (successfulHandoffs.length === 0) return null;
155
+
156
+ const totalConfidence = successfulHandoffs.reduce((sum, h) => sum + h.confidence, 0);
157
+ return totalConfidence / successfulHandoffs.length;
158
+ }
159
+
160
+ /**
161
+ * Calculate escalation rate
162
+ */
163
+ calculateEscalationRate() {
164
+ const totalTasks = this.currentSession.taskCount;
165
+ return totalTasks > 0 ? this.currentSession.escalations / totalTasks : 0;
166
+ }
167
+
168
+ /**
169
+ * Generate comprehensive performance report
170
+ */
171
+ generateReport() {
172
+ const efficiency = this.calculateEfficiencyVsBaseline();
173
+ const duration = Date.now() - this.currentSession.startTime;
174
+
175
+ const report = {
176
+ timestamp: new Date().toISOString(),
177
+ sessionDuration: duration,
178
+ workspace: this.workspace,
179
+
180
+ // Core metrics
181
+ taskCount: this.currentSession.taskCount,
182
+ totalHandoffs: this.currentSession.handoffs.length,
183
+ escalationCount: this.currentSession.escalations,
184
+
185
+ // Performance metrics
186
+ escalationRate: this.calculateEscalationRate(),
187
+ averageConfidence: this.calculateAverageConfidence(),
188
+
189
+ // Efficiency metrics
190
+ efficiency: efficiency ? {
191
+ tokenSavingsPercentage: (efficiency.tokenSavings * 100).toFixed(1),
192
+ costSavingsUSD: efficiency.costSavingsUSD.toFixed(4),
193
+ escalationRate: (efficiency.escalationRate * 100).toFixed(1),
194
+ averageConfidence: efficiency.averageConfidence ? (efficiency.averageConfidence * 100).toFixed(1) : null
195
+ } : null,
196
+
197
+ // Cost metrics
198
+ totalCostUSD: this.currentSession.totalCostUSD.toFixed(4),
199
+ totalTokensUsed: this.currentSession.totalTokensUsed,
200
+ averageCostPerTask: this.currentSession.taskCount > 0 ?
201
+ (this.currentSession.totalCostUSD / this.currentSession.taskCount).toFixed(4) : null,
202
+
203
+ // Tier distribution
204
+ tierDistribution: this.calculateTierDistribution(),
205
+
206
+ // Performance indicators
207
+ indicators: this.generatePerformanceIndicators(efficiency),
208
+
209
+ // Raw session data
210
+ session: this.currentSession
211
+ };
212
+
213
+ return report;
214
+ }
215
+
216
+ /**
217
+ * Calculate tier usage distribution
218
+ */
219
+ calculateTierDistribution() {
220
+ const tierCounts = { worker: 0, ic: 0, manager: 0 };
221
+
222
+ this.currentSession.handoffs.forEach(handoff => {
223
+ const tier = handoff.toTier || handoff.tier;
224
+ if (tierCounts.hasOwnProperty(tier)) {
225
+ tierCounts[tier]++;
226
+ }
227
+ });
228
+
229
+ const total = Object.values(tierCounts).reduce((sum, count) => sum + count, 0);
230
+
231
+ if (total === 0) return tierCounts;
232
+
233
+ return {
234
+ worker: { count: tierCounts.worker, percentage: (tierCounts.worker / total * 100).toFixed(1) },
235
+ ic: { count: tierCounts.ic, percentage: (tierCounts.ic / total * 100).toFixed(1) },
236
+ manager: { count: tierCounts.manager, percentage: (tierCounts.manager / total * 100).toFixed(1) }
237
+ };
238
+ }
239
+
240
+ /**
241
+ * Generate performance indicators and recommendations
242
+ */
243
+ generatePerformanceIndicators(efficiency) {
244
+ const indicators = [];
245
+
246
+ if (efficiency) {
247
+ // Token savings indicator
248
+ if (efficiency.tokenSavings > 0.5) {
249
+ indicators.push({
250
+ type: 'excellent',
251
+ metric: 'token_efficiency',
252
+ message: `Excellent token efficiency: ${(efficiency.tokenSavings * 100).toFixed(1)}% savings vs baseline`,
253
+ recommendation: 'Continue current routing strategy'
254
+ });
255
+ } else if (efficiency.tokenSavings > 0.2) {
256
+ indicators.push({
257
+ type: 'good',
258
+ metric: 'token_efficiency',
259
+ message: `Good token efficiency: ${(efficiency.tokenSavings * 100).toFixed(1)}% savings`,
260
+ recommendation: 'Consider optimizing task classification for better tier routing'
261
+ });
262
+ } else {
263
+ indicators.push({
264
+ type: 'warning',
265
+ metric: 'token_efficiency',
266
+ message: `Low token efficiency: only ${(efficiency.tokenSavings * 100).toFixed(1)}% savings`,
267
+ recommendation: 'Review task routing - too many high-tier operations for simple tasks'
268
+ });
269
+ }
270
+
271
+ // Escalation rate indicator
272
+ if (efficiency.escalationRate <= BASELINES.averageEscalationRate) {
273
+ indicators.push({
274
+ type: 'good',
275
+ metric: 'escalation_rate',
276
+ message: `Healthy escalation rate: ${(efficiency.escalationRate * 100).toFixed(1)}%`,
277
+ recommendation: 'Task complexity assessment is working well'
278
+ });
279
+ } else {
280
+ indicators.push({
281
+ type: 'warning',
282
+ metric: 'escalation_rate',
283
+ message: `High escalation rate: ${(efficiency.escalationRate * 100).toFixed(1)}%`,
284
+ recommendation: 'Consider starting tasks at higher tiers or improving initial classification'
285
+ });
286
+ }
287
+
288
+ // Confidence indicator
289
+ if (efficiency.averageConfidence >= BASELINES.targetConfidence) {
290
+ indicators.push({
291
+ type: 'excellent',
292
+ metric: 'confidence',
293
+ message: `High confidence: ${(efficiency.averageConfidence * 100).toFixed(1)}%`,
294
+ recommendation: 'Models are well-matched to task complexity'
295
+ });
296
+ } else if (efficiency.averageConfidence >= 0.6) {
297
+ indicators.push({
298
+ type: 'good',
299
+ metric: 'confidence',
300
+ message: `Moderate confidence: ${(efficiency.averageConfidence * 100).toFixed(1)}%`,
301
+ recommendation: 'Consider task decomposition or tier adjustment'
302
+ });
303
+ } else {
304
+ indicators.push({
305
+ type: 'warning',
306
+ metric: 'confidence',
307
+ message: `Low confidence: ${(efficiency.averageConfidence * 100).toFixed(1)}%`,
308
+ recommendation: 'Review task complexity vs model capabilities'
309
+ });
310
+ }
311
+ }
312
+
313
+ return indicators;
314
+ }
315
+
316
+ /**
317
+ * Save session report to persistent storage
318
+ */
319
+ saveSessionReport() {
320
+ const report = this.generateReport();
321
+ const reportsPath = join(this.metricsDir, 'session-reports.jsonl');
322
+
323
+ atomicAppendJSONL(reportsPath, report);
324
+
325
+ // Also save as individual report file
326
+ const reportId = `session-${this.currentSession.startTime}`;
327
+ const reportPath = join(this.metricsDir, `${reportId}.json`);
328
+ atomicWriteJSON(reportPath, report);
329
+
330
+ return { reportId, reportPath, report };
331
+ }
332
+
333
+ /**
334
+ * Update running statistics
335
+ */
336
+ updateRunningStats() {
337
+ const statsPath = join(this.metricsDir, 'running-stats.json');
338
+
339
+ const report = this.generateReport();
340
+
341
+ return lockedReadModifyWrite(statsPath, (stats) => {
342
+ const updated = stats || {
343
+ totalSessions: 0,
344
+ totalTasks: 0,
345
+ totalCostUSD: 0,
346
+ totalTokensUsed: 0,
347
+ averageEfficiency: 0,
348
+ averageConfidence: 0,
349
+ averageEscalationRate: 0,
350
+ lastUpdated: null
351
+ };
352
+
353
+ updated.totalSessions++;
354
+ updated.totalTasks += report.taskCount;
355
+ updated.totalCostUSD += parseFloat(report.totalCostUSD);
356
+ updated.totalTokensUsed += report.totalTokensUsed;
357
+
358
+ // Running averages
359
+ if (report.efficiency) {
360
+ const newEfficiency = parseFloat(report.efficiency.tokenSavingsPercentage) / 100;
361
+ updated.averageEfficiency = ((updated.averageEfficiency * (updated.totalSessions - 1)) + newEfficiency) / updated.totalSessions;
362
+
363
+ if (report.averageConfidence) {
364
+ const newConfidence = parseFloat(report.efficiency.averageConfidence) / 100;
365
+ updated.averageConfidence = ((updated.averageConfidence * (updated.totalSessions - 1)) + newConfidence) / updated.totalSessions;
366
+ }
367
+
368
+ const newEscalationRate = parseFloat(report.efficiency.escalationRate) / 100;
369
+ updated.averageEscalationRate = ((updated.averageEscalationRate * (updated.totalSessions - 1)) + newEscalationRate) / updated.totalSessions;
370
+ }
371
+
372
+ updated.lastUpdated = new Date().toISOString();
373
+
374
+ return updated;
375
+ }, {
376
+ totalSessions: 0,
377
+ totalTasks: 0,
378
+ totalCostUSD: 0,
379
+ totalTokensUsed: 0,
380
+ averageEfficiency: 0,
381
+ averageConfidence: 0,
382
+ averageEscalationRate: 0,
383
+ lastUpdated: null
384
+ });
385
+ }
386
+
387
+ /**
388
+ * End session and finalize metrics
389
+ */
390
+ endSession() {
391
+ const sessionReport = this.saveSessionReport();
392
+ const runningStats = this.updateRunningStats();
393
+
394
+ return {
395
+ ...sessionReport,
396
+ runningStats
397
+ };
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Global performance monitor instance
403
+ */
404
+ let globalMonitor = null;
405
+
406
+ /**
407
+ * Get or create global performance monitor
408
+ */
409
+ export function getPerformanceMonitor(workspace = process.cwd()) {
410
+ if (!globalMonitor) {
411
+ globalMonitor = new PerformanceMonitor(workspace);
412
+ }
413
+ return globalMonitor;
414
+ }
415
+
416
+ /**
417
+ * Track handoff with global monitor
418
+ */
419
+ export function trackHandoff(handoff) {
420
+ const monitor = getPerformanceMonitor();
421
+ return monitor.trackHandoff(handoff);
422
+ }
423
+
424
+ /**
425
+ * Generate performance report
426
+ */
427
+ export function generatePerformanceReport(workspace = process.cwd()) {
428
+ const monitor = getPerformanceMonitor(workspace);
429
+ return monitor.generateReport();
430
+ }
431
+
432
+ /**
433
+ * End session and save metrics
434
+ */
435
+ export function endPerformanceSession(workspace = process.cwd()) {
436
+ if (!globalMonitor) return null;
437
+
438
+ const result = globalMonitor.endSession();
439
+ globalMonitor = null; // Reset for next session
440
+
441
+ return result;
442
+ }