@miller-tech/uap 1.0.0 → 1.3.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 (129) hide show
  1. package/dist/benchmarks/benchmark.d.ts +8 -8
  2. package/dist/benchmarks/improved-benchmark.d.ts.map +1 -1
  3. package/dist/benchmarks/improved-benchmark.js +10 -23
  4. package/dist/benchmarks/improved-benchmark.js.map +1 -1
  5. package/dist/benchmarks/model-integration.d.ts.map +1 -1
  6. package/dist/benchmarks/model-integration.js +22 -23
  7. package/dist/benchmarks/model-integration.js.map +1 -1
  8. package/dist/bin/policy.js +67 -11
  9. package/dist/bin/policy.js.map +1 -1
  10. package/dist/cli/dashboard.d.ts +2 -1
  11. package/dist/cli/dashboard.d.ts.map +1 -1
  12. package/dist/cli/dashboard.js +399 -10
  13. package/dist/cli/dashboard.js.map +1 -1
  14. package/dist/cli/model.js +12 -12
  15. package/dist/cli/model.js.map +1 -1
  16. package/dist/cli/setup-wizard.d.ts.map +1 -1
  17. package/dist/cli/setup-wizard.js +24 -0
  18. package/dist/cli/setup-wizard.js.map +1 -1
  19. package/dist/coordination/deploy-batcher.d.ts +1 -0
  20. package/dist/coordination/deploy-batcher.d.ts.map +1 -1
  21. package/dist/coordination/deploy-batcher.js +24 -25
  22. package/dist/coordination/deploy-batcher.js.map +1 -1
  23. package/dist/dashboard/data-service.d.ts +94 -0
  24. package/dist/dashboard/data-service.d.ts.map +1 -0
  25. package/dist/dashboard/data-service.js +286 -0
  26. package/dist/dashboard/data-service.js.map +1 -0
  27. package/dist/dashboard/index.d.ts +5 -0
  28. package/dist/dashboard/index.d.ts.map +1 -0
  29. package/dist/dashboard/index.js +3 -0
  30. package/dist/dashboard/index.js.map +1 -0
  31. package/dist/dashboard/server.d.ts +15 -0
  32. package/dist/dashboard/server.d.ts.map +1 -0
  33. package/dist/dashboard/server.js +158 -0
  34. package/dist/dashboard/server.js.map +1 -0
  35. package/dist/mcp-router/session-stats.d.ts +9 -0
  36. package/dist/mcp-router/session-stats.d.ts.map +1 -1
  37. package/dist/mcp-router/session-stats.js +19 -3
  38. package/dist/mcp-router/session-stats.js.map +1 -1
  39. package/dist/memory/adaptive-context.d.ts +1 -0
  40. package/dist/memory/adaptive-context.d.ts.map +1 -1
  41. package/dist/memory/adaptive-context.js +4 -0
  42. package/dist/memory/adaptive-context.js.map +1 -1
  43. package/dist/memory/embeddings.d.ts.map +1 -1
  44. package/dist/memory/embeddings.js +4 -4
  45. package/dist/memory/embeddings.js.map +1 -1
  46. package/dist/memory/model-router.d.ts +1 -1
  47. package/dist/memory/model-router.d.ts.map +1 -1
  48. package/dist/memory/model-router.js +52 -1
  49. package/dist/memory/model-router.js.map +1 -1
  50. package/dist/memory/predictive-memory.d.ts.map +1 -1
  51. package/dist/memory/predictive-memory.js +4 -3
  52. package/dist/memory/predictive-memory.js.map +1 -1
  53. package/dist/models/analytics.d.ts +93 -0
  54. package/dist/models/analytics.d.ts.map +1 -0
  55. package/dist/models/analytics.js +205 -0
  56. package/dist/models/analytics.js.map +1 -0
  57. package/dist/models/execution-profiles.d.ts +6 -0
  58. package/dist/models/execution-profiles.d.ts.map +1 -1
  59. package/dist/models/execution-profiles.js +15 -0
  60. package/dist/models/execution-profiles.js.map +1 -1
  61. package/dist/models/executor.d.ts.map +1 -1
  62. package/dist/models/executor.js +51 -17
  63. package/dist/models/executor.js.map +1 -1
  64. package/dist/models/index.d.ts +2 -0
  65. package/dist/models/index.d.ts.map +1 -1
  66. package/dist/models/index.js +2 -0
  67. package/dist/models/index.js.map +1 -1
  68. package/dist/models/router.d.ts +8 -0
  69. package/dist/models/router.d.ts.map +1 -1
  70. package/dist/models/router.js +46 -21
  71. package/dist/models/router.js.map +1 -1
  72. package/dist/models/types.d.ts +26 -0
  73. package/dist/models/types.d.ts.map +1 -1
  74. package/dist/models/types.js +43 -4
  75. package/dist/models/types.js.map +1 -1
  76. package/dist/models/unified-router.d.ts.map +1 -1
  77. package/dist/models/unified-router.js +4 -0
  78. package/dist/models/unified-router.js.map +1 -1
  79. package/dist/policies/database-manager.d.ts +1 -0
  80. package/dist/policies/database-manager.d.ts.map +1 -1
  81. package/dist/policies/database-manager.js +14 -2
  82. package/dist/policies/database-manager.js.map +1 -1
  83. package/dist/policies/enforced-tool-router.d.ts +2 -2
  84. package/dist/policies/enforced-tool-router.d.ts.map +1 -1
  85. package/dist/policies/enforced-tool-router.js +4 -4
  86. package/dist/policies/enforced-tool-router.js.map +1 -1
  87. package/dist/policies/policy-gate.d.ts +2 -2
  88. package/dist/policies/policy-gate.d.ts.map +1 -1
  89. package/dist/policies/policy-gate.js +6 -4
  90. package/dist/policies/policy-gate.js.map +1 -1
  91. package/dist/policies/policy-memory.d.ts +3 -0
  92. package/dist/policies/policy-memory.d.ts.map +1 -1
  93. package/dist/policies/policy-memory.js +11 -0
  94. package/dist/policies/policy-memory.js.map +1 -1
  95. package/dist/policies/schemas/policy.d.ts +3 -0
  96. package/dist/policies/schemas/policy.d.ts.map +1 -1
  97. package/dist/policies/schemas/policy.js +1 -0
  98. package/dist/policies/schemas/policy.js.map +1 -1
  99. package/dist/tasks/coordination.d.ts +18 -0
  100. package/dist/tasks/coordination.d.ts.map +1 -1
  101. package/dist/tasks/coordination.js +59 -1
  102. package/dist/tasks/coordination.js.map +1 -1
  103. package/dist/tasks/event-bus.d.ts +91 -0
  104. package/dist/tasks/event-bus.d.ts.map +1 -0
  105. package/dist/tasks/event-bus.js +123 -0
  106. package/dist/tasks/event-bus.js.map +1 -0
  107. package/dist/tasks/service.d.ts +5 -0
  108. package/dist/tasks/service.d.ts.map +1 -1
  109. package/dist/tasks/service.js +59 -0
  110. package/dist/tasks/service.js.map +1 -1
  111. package/dist/telemetry/session-telemetry.d.ts.map +1 -1
  112. package/dist/telemetry/session-telemetry.js +3 -0
  113. package/dist/telemetry/session-telemetry.js.map +1 -1
  114. package/dist/utils/concurrency-pool.d.ts +51 -0
  115. package/dist/utils/concurrency-pool.d.ts.map +1 -0
  116. package/dist/utils/concurrency-pool.js +80 -0
  117. package/dist/utils/concurrency-pool.js.map +1 -0
  118. package/dist/utils/system-resources.d.ts +47 -0
  119. package/dist/utils/system-resources.d.ts.map +1 -0
  120. package/dist/utils/system-resources.js +92 -0
  121. package/dist/utils/system-resources.js.map +1 -0
  122. package/docs/BENCHMARK_GAPS_AND_PLAN.md +146 -0
  123. package/docs/PARALLELISM_GAPS_AND_OPTIONS.md +422 -0
  124. package/docs/UAP_OPTIMIZATION_PLAN.md +638 -0
  125. package/docs/getting-started/INTEGRATION.md +193 -14
  126. package/docs/opencode-integration-guide.md +740 -0
  127. package/docs/opencode-integration-quickref.md +180 -0
  128. package/package.json +4 -1
  129. package/templates/hooks/session-start.sh +8 -1
@@ -1,7 +1,8 @@
1
- type DashboardAction = 'overview' | 'tasks' | 'agents' | 'memory' | 'progress' | 'stats' | 'session' | 'benchmark';
1
+ type DashboardAction = 'overview' | 'tasks' | 'agents' | 'memory' | 'progress' | 'stats' | 'session' | 'benchmark' | 'policies' | 'models' | 'serve' | 'export' | 'history';
2
2
  interface DashboardOptions {
3
3
  verbose?: boolean;
4
4
  compact?: boolean;
5
+ taskId?: string;
5
6
  }
6
7
  export declare function dashboardCommand(action: DashboardAction, options?: DashboardOptions): Promise<void>;
7
8
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/cli/dashboard.ts"],"names":[],"mappings":"AA+BA,KAAK,eAAe,GAChB,UAAU,GACV,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,OAAO,GACP,SAAS,GACT,WAAW,CAAC;AAEhB,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAyvCD;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAuM5C;AAID;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,IAAI,CA0QpC"}
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/cli/dashboard.ts"],"names":[],"mappings":"AAqCA,KAAK,eAAe,GAChB,UAAU,GACV,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,OAAO,GACP,SAAS,GACT,WAAW,GACX,UAAU,GACV,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,CAAC;AAEd,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CA0Cf;AA0qDD;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAuM5C;AAID;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,IAAI,CA0QpC"}
@@ -10,6 +10,12 @@ import { SQLiteShortTermMemory } from '../memory/short-term/sqlite.js';
10
10
  import { progressBar, stackedBar, stackedBarLegend, horizontalBarChart, table, tree, box, sectionHeader, keyValue, miniGauge, statusBadge, divider, bulletList, columns, } from './visualize.js';
11
11
  import { STATUS_ICONS, TYPE_ICONS, PRIORITY_LABELS } from '../tasks/types.js';
12
12
  import { globalSessionStats } from '../mcp-router/session-stats.js';
13
+ import { getPolicyMemoryManager } from '../policies/policy-memory.js';
14
+ import { getPolicyGate } from '../policies/policy-gate.js';
15
+ import { ModelRouter } from '../models/router.js';
16
+ import { ModelPresets } from '../models/types.js';
17
+ import { getModelAnalytics } from '../models/analytics.js';
18
+ import { detectExecutionProfile } from '../models/execution-profiles.js';
13
19
  export async function dashboardCommand(action, options = {}) {
14
20
  switch (action) {
15
21
  case 'overview':
@@ -36,6 +42,93 @@ export async function dashboardCommand(action, options = {}) {
36
42
  case 'benchmark':
37
43
  showDashboard();
38
44
  break;
45
+ case 'policies':
46
+ await showPoliciesDashboard(options);
47
+ break;
48
+ case 'models':
49
+ await showModelsDashboard(options);
50
+ break;
51
+ case 'serve':
52
+ await serveDashboard(options);
53
+ break;
54
+ case 'export':
55
+ await exportDashboard(options);
56
+ break;
57
+ case 'history':
58
+ await showHistory(options);
59
+ break;
60
+ }
61
+ }
62
+ async function serveDashboard(_options) {
63
+ const { startDashboardServer } = await import('../dashboard/server.js');
64
+ const server = startDashboardServer({ port: 3847 });
65
+ // Keep alive until Ctrl+C
66
+ process.on('SIGINT', () => {
67
+ console.log('\nShutting down dashboard server...');
68
+ server.close();
69
+ process.exit(0);
70
+ });
71
+ process.on('SIGTERM', () => {
72
+ server.close();
73
+ process.exit(0);
74
+ });
75
+ }
76
+ async function exportDashboard(options) {
77
+ const { getDashboardData } = await import('../dashboard/data-service.js');
78
+ const data = await getDashboardData();
79
+ if (options.verbose) {
80
+ // CSV-like output for key tables
81
+ console.log('# Policies');
82
+ console.log('name,level,stage,category,active');
83
+ for (const p of data.policies) {
84
+ console.log(`${p.name},${p.level},${p.enforcementStage},${p.category},${p.isActive}`);
85
+ }
86
+ console.log('');
87
+ console.log('# Model Usage');
88
+ console.log('model,tasks,tokens_in,tokens_out,cost,success_rate');
89
+ for (const m of data.models.sessionUsage) {
90
+ console.log(`${m.modelId},${m.taskCount},${m.totalTokensIn},${m.totalTokensOut},${m.totalCost},${m.successRate}`);
91
+ }
92
+ }
93
+ else {
94
+ console.log(JSON.stringify(data, null, 2));
95
+ }
96
+ }
97
+ async function showHistory(_options) {
98
+ const cwd = process.cwd();
99
+ const snapshotDbPath = join(cwd, 'agents', 'data', 'memory', 'session_snapshots.db');
100
+ if (!existsSync(snapshotDbPath)) {
101
+ console.log(chalk.dim('No session history found. Snapshots are saved automatically.'));
102
+ return;
103
+ }
104
+ try {
105
+ const db = new Database(snapshotDbPath, { readonly: true });
106
+ const rows = db
107
+ .prepare('SELECT id, timestamp, duration_ms, total_cost, tasks_completed, models_used FROM session_snapshots ORDER BY timestamp DESC LIMIT 20')
108
+ .all();
109
+ db.close();
110
+ if (rows.length === 0) {
111
+ console.log(chalk.dim('No session snapshots recorded yet.'));
112
+ return;
113
+ }
114
+ console.log('');
115
+ console.log(chalk.bold.cyan(' Session History'));
116
+ console.log(divider(70));
117
+ console.log('');
118
+ console.log(` ${'Timestamp'.padEnd(22)} ${'Duration'.padEnd(12)} ${'Cost'.padEnd(10)} ${'Tasks'.padEnd(8)} Models`);
119
+ console.log(` ${'─'.repeat(22)} ${'─'.repeat(12)} ${'─'.repeat(10)} ${'─'.repeat(8)} ${'─'.repeat(16)}`);
120
+ for (const row of rows) {
121
+ const ts = row.timestamp.slice(0, 19);
122
+ const dur = row.duration_ms ? `${Math.round(row.duration_ms / 1000)}s` : '?';
123
+ const cost = row.total_cost ? `$${row.total_cost.toFixed(4)}` : '$0';
124
+ const tasks = String(row.tasks_completed || 0);
125
+ const models = row.models_used ? JSON.parse(row.models_used).join(', ') : '?';
126
+ console.log(` ${ts.padEnd(22)} ${dur.padEnd(12)} ${cost.padEnd(10)} ${tasks.padEnd(8)} ${models}`);
127
+ }
128
+ console.log('');
129
+ }
130
+ catch (error) {
131
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
39
132
  }
40
133
  }
41
134
  async function showOverview(_options) {
@@ -557,6 +650,22 @@ async function showMemoryDashboard(_options) {
557
650
  for (const line of tree(layers))
558
651
  console.log(line);
559
652
  console.log('');
653
+ // Compression stats from session
654
+ console.log(sectionHeader('Context Compression'));
655
+ console.log('');
656
+ const sessionStats = globalSessionStats.getSummary();
657
+ if (sessionStats.totalCalls > 0) {
658
+ const rawKB = Math.round(sessionStats.totalRawBytes / 1024);
659
+ const ctxKB = Math.round(sessionStats.totalContextBytes / 1024);
660
+ console.log(` ${chalk.white('Raw bytes'.padEnd(25))} ${chalk.bold(rawKB + ' KB')}`);
661
+ console.log(` ${chalk.white('Context bytes'.padEnd(25))} ${chalk.bold(ctxKB + ' KB')}`);
662
+ console.log(` ${chalk.white('Savings'.padEnd(25))} ${chalk.green(sessionStats.savingsPercent)}`);
663
+ console.log(` ${chalk.white('Tool calls'.padEnd(25))} ${chalk.bold(String(sessionStats.totalCalls))}`);
664
+ }
665
+ else {
666
+ console.log(chalk.dim(' No compression data this session'));
667
+ }
668
+ console.log('');
560
669
  }
561
670
  catch (error) {
562
671
  spinner.fail('Failed to load memory dashboard');
@@ -1081,19 +1190,30 @@ async function showSessionDashboard(options) {
1081
1190
  console.log(chalk.dim(' Droids: None registered'));
1082
1191
  }
1083
1192
  console.log('');
1084
- // Policies
1193
+ // Policies (DB-driven)
1085
1194
  console.log(sectionHeader('Policies'));
1086
1195
  console.log('');
1087
- const policyItems = [
1088
- { text: 'IaC State Parity', status: 'ok' },
1089
- { text: 'Mandatory File Backup', status: 'ok' },
1090
- ];
1091
- const imgPolicyPath = join(cwd, 'policies/image-asset-verification.md');
1092
- if (existsSync(imgPolicyPath)) {
1093
- policyItems.push({ text: 'Image & Asset Verification', status: 'info' });
1196
+ try {
1197
+ const policyMgr = getPolicyMemoryManager();
1198
+ const allPolicies = await policyMgr.getAllPolicies();
1199
+ if (allPolicies.length > 0) {
1200
+ for (const policy of allPolicies) {
1201
+ const stageLabel = policy.enforcementStage || 'pre-exec';
1202
+ const levelColor = policy.level === 'REQUIRED'
1203
+ ? chalk.red
1204
+ : policy.level === 'RECOMMENDED'
1205
+ ? chalk.yellow
1206
+ : chalk.dim;
1207
+ console.log(` ${levelColor(policy.level.padEnd(14))} ${policy.name.slice(0, 30).padEnd(30)} ${chalk.dim(stageLabel)}`);
1208
+ }
1209
+ }
1210
+ else {
1211
+ console.log(chalk.dim(' No policies configured. Add with: uap policy add -f <file>'));
1212
+ }
1213
+ }
1214
+ catch {
1215
+ console.log(chalk.dim(' Policy DB not initialized'));
1094
1216
  }
1095
- for (const line of bulletList(policyItems))
1096
- console.log(line);
1097
1217
  console.log('');
1098
1218
  // Open loops
1099
1219
  if (openLoops.length > 0) {
@@ -1121,6 +1241,275 @@ async function showSessionDashboard(options) {
1121
1241
  console.error(chalk.red(error instanceof Error ? error.message : String(error)));
1122
1242
  }
1123
1243
  }
1244
+ async function showPoliciesDashboard(options) {
1245
+ const spinner = ora('Loading policies dashboard...').start();
1246
+ try {
1247
+ const policyMgr = getPolicyMemoryManager();
1248
+ const gate = getPolicyGate();
1249
+ const allPolicies = await policyMgr.getAllPolicies();
1250
+ spinner.stop();
1251
+ console.log('');
1252
+ console.log(chalk.bold.cyan(' UAP Policies Dashboard'));
1253
+ console.log(divider(62));
1254
+ console.log('');
1255
+ // Active policies table
1256
+ console.log(sectionHeader(`Active Policies (${allPolicies.length})`));
1257
+ console.log('');
1258
+ if (allPolicies.length === 0) {
1259
+ console.log(chalk.dim(' No policies configured. Add with: uap policy add -f <file>'));
1260
+ }
1261
+ else {
1262
+ console.log(` ${'Name'.padEnd(28)} ${'Level'.padEnd(14)} ${'Stage'.padEnd(12)} ${'Category'.padEnd(10)} Status`);
1263
+ console.log(` ${'─'.repeat(28)} ${'─'.repeat(14)} ${'─'.repeat(12)} ${'─'.repeat(10)} ${'─'.repeat(6)}`);
1264
+ for (const policy of allPolicies) {
1265
+ const stage = policy.enforcementStage || 'pre-exec';
1266
+ const status = policy.isActive ? chalk.green('ON') : chalk.red('OFF');
1267
+ const levelColor = policy.level === 'REQUIRED'
1268
+ ? chalk.red
1269
+ : policy.level === 'RECOMMENDED'
1270
+ ? chalk.yellow
1271
+ : chalk.dim;
1272
+ console.log(` ${policy.name.slice(0, 28).padEnd(28)} ${levelColor(policy.level.padEnd(14))} ${stage.padEnd(12)} ${policy.category.padEnd(10)} ${status}`);
1273
+ }
1274
+ }
1275
+ console.log('');
1276
+ // Enforcement stages breakdown
1277
+ const stageGroups = {
1278
+ 'pre-exec': 0,
1279
+ 'post-exec': 0,
1280
+ review: 0,
1281
+ always: 0,
1282
+ };
1283
+ for (const p of allPolicies) {
1284
+ const stage = p.enforcementStage || 'pre-exec';
1285
+ stageGroups[stage] = (stageGroups[stage] || 0) + 1;
1286
+ }
1287
+ console.log(sectionHeader('Enforcement Stages'));
1288
+ console.log('');
1289
+ for (const [stage, count] of Object.entries(stageGroups)) {
1290
+ const barLen = Math.min(count * 5, 30);
1291
+ const bar = chalk.cyan('\u2588'.repeat(barLen)) + chalk.dim('\u2591'.repeat(30 - barLen));
1292
+ console.log(` ${stage.padEnd(12)} ${bar} ${count} policies`);
1293
+ }
1294
+ console.log('');
1295
+ // Level breakdown
1296
+ const levelGroups = { REQUIRED: 0, RECOMMENDED: 0, OPTIONAL: 0 };
1297
+ for (const p of allPolicies) {
1298
+ levelGroups[p.level] = (levelGroups[p.level] || 0) + 1;
1299
+ }
1300
+ console.log(sectionHeader('Enforcement Levels'));
1301
+ console.log('');
1302
+ for (const [level, count] of Object.entries(levelGroups)) {
1303
+ const color = level === 'REQUIRED' ? chalk.red : level === 'RECOMMENDED' ? chalk.yellow : chalk.dim;
1304
+ console.log(` ${color(level.padEnd(14))} ${chalk.bold(String(count))}`);
1305
+ }
1306
+ console.log('');
1307
+ // Audit trail
1308
+ const auditEntries = await gate.getAuditTrail(undefined, 10);
1309
+ if (auditEntries.length > 0) {
1310
+ console.log(sectionHeader('Recent Audit Trail'));
1311
+ console.log('');
1312
+ for (const entry of auditEntries) {
1313
+ const icon = entry.allowed ? chalk.green('PASS') : chalk.red('BLOCK');
1314
+ const time = typeof entry.executedAt === 'string' ? entry.executedAt.slice(0, 19) : '';
1315
+ const op = typeof entry.operation === 'string' ? entry.operation : '';
1316
+ const reason = typeof entry.reason === 'string' ? entry.reason.slice(0, 40) : '';
1317
+ console.log(` ${chalk.dim(time)} ${icon} ${op.padEnd(20)} ${chalk.dim(reason)}`);
1318
+ }
1319
+ }
1320
+ else {
1321
+ console.log(chalk.dim(' No audit trail entries yet'));
1322
+ }
1323
+ console.log('');
1324
+ // Per-task filtering
1325
+ if (options.taskId) {
1326
+ console.log(sectionHeader(`Policy Checks for Task: ${options.taskId}`));
1327
+ console.log('');
1328
+ const taskAudit = await gate.getAuditTrail(undefined, 50);
1329
+ const taskEntries = taskAudit.filter((e) => e.taskId === options.taskId);
1330
+ if (taskEntries.length > 0) {
1331
+ for (const entry of taskEntries) {
1332
+ const icon = entry.allowed ? chalk.green('PASS') : chalk.red('BLOCK');
1333
+ console.log(` ${icon} ${entry.operation} - ${entry.reason || 'OK'}`);
1334
+ }
1335
+ }
1336
+ else {
1337
+ console.log(chalk.dim(' No policy checks recorded for this task'));
1338
+ }
1339
+ console.log('');
1340
+ }
1341
+ // Help
1342
+ console.log(chalk.dim(' Toggle: uap policy toggle <id> --off'));
1343
+ console.log(chalk.dim(' Stage: uap policy stage <id> -s post-exec'));
1344
+ console.log(chalk.dim(' Level: uap policy level <id> -l OPTIONAL'));
1345
+ console.log('');
1346
+ }
1347
+ catch (error) {
1348
+ spinner.fail('Failed to load policies dashboard');
1349
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
1350
+ }
1351
+ }
1352
+ async function showModelsDashboard(options) {
1353
+ const spinner = ora('Loading models dashboard...').start();
1354
+ try {
1355
+ // Load UAP config
1356
+ const configPath = join(process.cwd(), '.uap.json');
1357
+ let mmConfig = {
1358
+ enabled: true,
1359
+ models: ['opus-4.6', 'qwen35'],
1360
+ roles: { planner: 'opus-4.6', executor: 'qwen35', fallback: 'qwen35' },
1361
+ routingStrategy: 'balanced',
1362
+ };
1363
+ if (existsSync(configPath)) {
1364
+ try {
1365
+ const raw = JSON.parse(readFileSync(configPath, 'utf-8'));
1366
+ if (raw.multiModel)
1367
+ mmConfig = raw.multiModel;
1368
+ }
1369
+ catch {
1370
+ /* use defaults */
1371
+ }
1372
+ }
1373
+ const router = new ModelRouter(mmConfig);
1374
+ const analytics = getModelAnalytics();
1375
+ spinner.stop();
1376
+ console.log('');
1377
+ console.log(chalk.bold.cyan(' UAP Model Dashboard'));
1378
+ console.log(divider(62));
1379
+ console.log('');
1380
+ // Active configuration
1381
+ console.log(sectionHeader('Active Configuration'));
1382
+ console.log('');
1383
+ const roles = mmConfig.roles || { planner: 'opus-4.6', executor: 'qwen35', fallback: 'qwen35' };
1384
+ const plannerPreset = ModelPresets[roles.planner || 'opus-4.6'];
1385
+ const executorPreset = ModelPresets[roles.executor || 'qwen35'];
1386
+ const fallbackPreset = ModelPresets[roles.fallback || 'qwen35'];
1387
+ const roleRows = [
1388
+ [
1389
+ 'Planner',
1390
+ roles.planner || 'opus-4.6',
1391
+ plannerPreset?.name || '?',
1392
+ `$${(plannerPreset?.costPer1MInput || 0).toFixed(2)}/$${(plannerPreset?.costPer1MOutput || 0).toFixed(2)}`,
1393
+ ],
1394
+ [
1395
+ 'Executor',
1396
+ roles.executor || 'qwen35',
1397
+ executorPreset?.name || '?',
1398
+ `$${(executorPreset?.costPer1MInput || 0).toFixed(2)}/$${(executorPreset?.costPer1MOutput || 0).toFixed(2)}`,
1399
+ ],
1400
+ ['Reviewer', roles.reviewer || roles.planner || 'opus-4.6', plannerPreset?.name || '?', ''],
1401
+ ['Fallback', roles.fallback || 'qwen35', fallbackPreset?.name || '?', ''],
1402
+ ];
1403
+ for (const [role, id, name, cost] of roleRows) {
1404
+ const roleColor = role === 'Planner' ? chalk.green : role === 'Executor' ? chalk.blue : chalk.dim;
1405
+ console.log(` ${roleColor(role.padEnd(10))} ${chalk.cyan(id.padEnd(14))} ${name.padEnd(22)} ${chalk.dim(cost)}`);
1406
+ }
1407
+ console.log(` ${'Strategy'.padEnd(10)} ${chalk.cyan(mmConfig.routingStrategy)}`);
1408
+ console.log('');
1409
+ // Routing matrix
1410
+ console.log(sectionHeader('Routing Matrix'));
1411
+ console.log('');
1412
+ console.log(` ${'Complexity'.padEnd(12)} ${'Model'.padEnd(16)} ${'Est. Cost'}`);
1413
+ console.log(` ${'─'.repeat(12)} ${'─'.repeat(16)} ${'─'.repeat(10)}`);
1414
+ for (const complexity of ['low', 'medium', 'high', 'critical']) {
1415
+ const result = router.classifyTask(`A ${complexity} complexity task`);
1416
+ const model = result.suggestedModel;
1417
+ const preset = ModelPresets[model];
1418
+ const cost = preset ? router.estimateCost(preset, 10000, 5000) : 0;
1419
+ const complexityColor = complexity === 'critical'
1420
+ ? chalk.red
1421
+ : complexity === 'high'
1422
+ ? chalk.yellow
1423
+ : complexity === 'medium'
1424
+ ? chalk.blue
1425
+ : chalk.green;
1426
+ console.log(` ${complexityColor(complexity.padEnd(12))} ${chalk.cyan(model.padEnd(16))} $${cost.toFixed(4)}`);
1427
+ }
1428
+ console.log('');
1429
+ // Session usage from analytics
1430
+ const sessionUsage = analytics.getSessionUsage();
1431
+ if (sessionUsage.length > 0) {
1432
+ console.log(sectionHeader('Session Usage'));
1433
+ console.log('');
1434
+ console.log(` ${'Model'.padEnd(14)} ${'Tasks'.padEnd(7)} ${'Tokens In'.padEnd(12)} ${'Tokens Out'.padEnd(12)} ${'Cost'.padEnd(10)} ${'Success'}`);
1435
+ console.log(` ${'─'.repeat(14)} ${'─'.repeat(7)} ${'─'.repeat(12)} ${'─'.repeat(12)} ${'─'.repeat(10)} ${'─'.repeat(7)}`);
1436
+ for (const usage of sessionUsage) {
1437
+ const rate = (usage.successRate * 100).toFixed(1) + '%';
1438
+ console.log(` ${chalk.cyan(usage.modelId.padEnd(14))} ${String(usage.taskCount).padEnd(7)} ${String(usage.totalTokensIn).padEnd(12)} ${String(usage.totalTokensOut).padEnd(12)} $${usage.totalCost.toFixed(4).padEnd(9)} ${rate}`);
1439
+ }
1440
+ console.log('');
1441
+ const totalCost = analytics.getTotalCost();
1442
+ console.log(` ${chalk.bold('Total session cost:')} $${totalCost.toFixed(4)}`);
1443
+ console.log('');
1444
+ }
1445
+ else {
1446
+ console.log(chalk.dim(' No model usage recorded this session'));
1447
+ console.log('');
1448
+ }
1449
+ // Execution profile for executor
1450
+ const executorModel = roles.executor || 'qwen35';
1451
+ const executorApiModel = ModelPresets[executorModel]?.apiModel || executorModel;
1452
+ const profile = detectExecutionProfile(executorApiModel);
1453
+ console.log(sectionHeader(`Execution Profile: ${profile.name}`));
1454
+ console.log('');
1455
+ const profileConfig = profile.config;
1456
+ const flagPairs = [
1457
+ ['domainHints', profileConfig.domainHints],
1458
+ ['webSearch', profileConfig.webSearch],
1459
+ ['reflectionCheckpoints', profileConfig.reflectionCheckpoints],
1460
+ ['temperature', profileConfig.temperature],
1461
+ ['loopEscapeThreshold', profileConfig.loopEscapeThreshold],
1462
+ ['toolChoiceForce', profileConfig.toolChoiceForce],
1463
+ ['softBudget', profileConfig.softBudget],
1464
+ ['hardBudget', profileConfig.hardBudget],
1465
+ ];
1466
+ const flagLines = [];
1467
+ for (const [key, val] of flagPairs) {
1468
+ const display = typeof val === 'boolean'
1469
+ ? val
1470
+ ? chalk.green('ON')
1471
+ : chalk.red('OFF')
1472
+ : chalk.cyan(String(val));
1473
+ flagLines.push(`${key}: ${display}`);
1474
+ }
1475
+ // Print 3 per line
1476
+ for (let i = 0; i < flagLines.length; i += 3) {
1477
+ const chunk = flagLines.slice(i, i + 3);
1478
+ console.log(` ${chunk.map((f) => f.padEnd(28)).join('')}`);
1479
+ }
1480
+ console.log('');
1481
+ // Per-task view
1482
+ if (options.taskId) {
1483
+ console.log(sectionHeader(`Model Usage for Task: ${options.taskId}`));
1484
+ console.log('');
1485
+ const taskOutcomes = analytics.getTaskOutcomes(options.taskId);
1486
+ if (taskOutcomes.length > 0) {
1487
+ for (const outcome of taskOutcomes) {
1488
+ const icon = outcome.success ? chalk.green('OK') : chalk.red('FAIL');
1489
+ console.log(` ${icon} ${chalk.cyan(outcome.modelId)} ${outcome.taskType} ${outcome.complexity} ${outcome.durationMs}ms $${outcome.cost.toFixed(4)}`);
1490
+ }
1491
+ }
1492
+ else {
1493
+ console.log(chalk.dim(' No outcomes recorded for this task'));
1494
+ }
1495
+ console.log('');
1496
+ }
1497
+ // Optimal routing suggestions
1498
+ const optimal = analytics.getOptimalRouting();
1499
+ if (Object.keys(optimal).length > 0) {
1500
+ console.log(sectionHeader('Optimal Routing (from history)'));
1501
+ console.log('');
1502
+ for (const [taskType, modelId] of Object.entries(optimal)) {
1503
+ console.log(` ${taskType.padEnd(16)} -> ${chalk.cyan(modelId)}`);
1504
+ }
1505
+ console.log('');
1506
+ }
1507
+ }
1508
+ catch (error) {
1509
+ spinner.fail('Failed to load models dashboard');
1510
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
1511
+ }
1512
+ }
1124
1513
  // ==================== Compact Session Summary (for post-task / pre-compact) ====================
1125
1514
  /**
1126
1515
  * Renders a compact session summary panel.