@miller-tech/uap 1.107.0 → 1.108.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miller-tech/uap",
3
- "version": "1.107.0",
3
+ "version": "1.108.0",
4
4
  "description": "Autonomous AI agent memory system with CLAUDE.md protocol enforcement",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -29,7 +29,7 @@
29
29
  "install:web": "bash scripts/setup/install-web.sh",
30
30
  "install:desktop": "bash scripts/setup/install-desktop.sh",
31
31
  "install:cloakbrowser": "tsx scripts/setup/install-cloakbrowser.ts",
32
- "postinstall": "echo '\n\u2728 Run: npx @miller-tech/uap init --interactive'",
32
+ "postinstall": "echo '\n Run: npx @miller-tech/uap init --interactive'",
33
33
  "version:patch": "bash scripts/version-bump.sh patch",
34
34
  "version:minor": "bash scripts/version-bump.sh minor",
35
35
  "version:major": "bash scripts/version-bump.sh major",
@@ -578,6 +578,23 @@
578
578
  </div>
579
579
  </div>
580
580
 
581
+ <!-- Token Savings by Influence -->
582
+ <div class="full-row" id="savings-panel">
583
+ <div class="panel">
584
+ <h2>Token Savings by Influence</h2>
585
+ <div id="savings-summary" style="margin-bottom:12px;font-size:14px"></div>
586
+ <div id="savings-table" class="table-wrap"><div class="empty">No savings data</div></div>
587
+ </div>
588
+ </div>
589
+
590
+ <!-- Orchestrations & Hierarchy -->
591
+ <div class="full-row" id="orch-panel">
592
+ <div class="panel">
593
+ <h2>Orchestrations &amp; Hierarchy <span style="font-size:11px;color:var(--fg3);font-weight:400" id="orch-label"></span></h2>
594
+ <div id="orch-tree"><div class="empty">No orchestrations yet</div></div>
595
+ </div>
596
+ </div>
597
+
581
598
  <!-- Task Board -->
582
599
  <div class="full-row" id="kanban-panel" style="display:none">
583
600
  <div class="panel">
@@ -1107,6 +1124,8 @@
1107
1124
  });
1108
1125
 
1109
1126
  safe('kanban', () => renderKanban(tasks));
1127
+ safe('savings', () => renderSavings(data.savingsByInfluence));
1128
+ safe('orchestration', () => renderOrchestration(data.orchestrationTree));
1110
1129
 
1111
1130
  safe('performance', () => {
1112
1131
  const hp = (data.performance||{}).hotPaths || [];
@@ -1135,6 +1154,60 @@
1135
1154
  const TYPE_ICONS = {task:'\u25C6',bug:'\uD83D\uDC1B',feature:'\u2728',epic:'\uD83C\uDFAF',chore:'\uD83D\uDD27',story:'\uD83D\uDCD6'};
1136
1155
  const PRIO_LABELS = ['P0','P1','P2','P3','P4'];
1137
1156
  let prevCardMap = new Map();
1157
+ function renderSavings(sv) {
1158
+ sv = sv || { influences: [], totalTokensSaved: 0, totalCostSavedUsd: 0 };
1159
+ const badge = (q) => {
1160
+ const c = q === 'measured' ? '#3fb950' : q === 'estimated' ? '#d29922' : '#484f58';
1161
+ return `<span style="color:${c};font-size:10px;text-transform:uppercase;border:1px solid ${c};border-radius:3px;padding:1px 5px">${q}</span>`;
1162
+ };
1163
+ setHTML('savings-summary',
1164
+ `<strong style="color:#58a6ff;font-size:18px">${fmt(sv.totalTokensSaved)}</strong> tokens · ` +
1165
+ `<strong style="color:#3fb950;font-size:18px">$${(sv.totalCostSavedUsd||0).toFixed(2)}</strong> saved across all UAP influences`);
1166
+ if (!sv.influences.length) { setHTML('savings-table', '<div class="empty">No savings data</div>'); return; }
1167
+ const rows = sv.influences.map(i =>
1168
+ `<tr><td>${esc(i.influence)}</td><td style="text-align:right">${fmt(i.tokensSaved)}</td>` +
1169
+ `<td style="text-align:right;color:#3fb950">$${(i.costSavedUsd||0).toFixed(4)}</td>` +
1170
+ `<td>${badge(i.quality)}</td><td style="color:var(--fg3);font-size:11px">${esc(i.detail||'')}</td></tr>`).join('');
1171
+ setHTML('savings-table',
1172
+ `<table><thead><tr><th>Influence</th><th style="text-align:right">Tokens saved</th>` +
1173
+ `<th style="text-align:right">Cost saved</th><th>Quality</th><th>Detail</th></tr></thead><tbody>${rows}</tbody></table>`);
1174
+ }
1175
+
1176
+ function orchNode(n, depth) {
1177
+ const pad = depth * 16;
1178
+ const sc = { done:'#3fb950', in_progress:'#58a6ff', blocked:'#f85149', failed:'#f85149', open:'#8b949e', pending:'#8b949e' }[n.status] || '#8b949e';
1179
+ const icon = n.type === 'epic' ? '🎯' : n.type === 'feature' ? '✨' : n.type === 'phase' ? '▶' : '•';
1180
+ const agents = (n.agents && n.agents.length) ? ` <span style="color:#a371f7;font-size:10px">[${n.agents.join(', ')}]</span>` : '';
1181
+ let html = `<div style="padding:3px 0 3px ${pad}px;border-left:1px solid var(--border)">` +
1182
+ `<span style="color:${sc}">●</span> ${icon} <span>${esc((n.title||n.id).slice(0,70))}</span>` +
1183
+ ` <span style="color:var(--fg3);font-size:10px">${n.status}</span>${agents}</div>`;
1184
+ for (const c of (n.children||[])) html += orchNode(c, depth + 1);
1185
+ return html;
1186
+ }
1187
+
1188
+ function renderOrchestration(ot) {
1189
+ ot = ot || { missions: [], ledger: null, agents: [], hasHierarchy: false };
1190
+ setText('orch-label', `${ot.missions.length} root(s) · ${ot.agents.length} agent(s)`);
1191
+ let html = '';
1192
+ if (ot.ledger) {
1193
+ const L = ot.ledger;
1194
+ html += `<div style="margin-bottom:14px;padding:10px;background:var(--bg2);border-radius:6px">` +
1195
+ `<div style="font-weight:600;margin-bottom:6px">Active build: ${L.mission.slice(0,80)} ` +
1196
+ `<span style="color:#58a6ff">${L.done}/${L.total} (${L.pct}%)</span></div>`;
1197
+ html += L.items.map(it => {
1198
+ const sc = { done:'#3fb950', in_progress:'#58a6ff', failed:'#f85149', pending:'#8b949e' }[it.status] || '#8b949e';
1199
+ const dep = it.deps && it.deps.length ? ` <span style="color:var(--fg3);font-size:10px">⇠ ${it.deps.join(',')}</span>` : '';
1200
+ return `<div style="padding:2px 0"><span style="color:${sc}">●</span> ${it.kind==='epic'?'🎯':'•'} ${esc(it.title.slice(0,70))} <span style="color:var(--fg3);font-size:10px">${it.status}</span>${dep}</div>`;
1201
+ }).join('');
1202
+ html += `</div>`;
1203
+ }
1204
+ const withKids = ot.missions.filter(m => (m.children||[]).length > 0);
1205
+ const shown = (withKids.length ? withKids : ot.missions).slice(0, 20);
1206
+ if (!ot.ledger && shown.length === 0) { setHTML('orch-tree', '<div class="empty">No orchestrations yet — run an epic/orchestrated build</div>'); return; }
1207
+ html += shown.map(m => orchNode(m, 0)).join('');
1208
+ setHTML('orch-tree', html);
1209
+ }
1210
+
1138
1211
  function renderKanban(tasks) {
1139
1212
  const items=tasks.items||[], cols={open:[],in_progress:[],blocked:[],done:[],wont_do:[]}, ncm=new Map();
1140
1213
  for (const i of items) { if(cols[i.status]) cols[i.status].push(i); ncm.set(i.id,i.status); }
@@ -1159,6 +1232,7 @@
1159
1232
 
1160
1233
  // ── Helpers ──
1161
1234
  function setText(id,val){const e=document.getElementById(id);if(e)e.textContent=String(val);}
1235
+ function setHTML(id,html){const e=document.getElementById(id);if(e)e.innerHTML=html;}
1162
1236
  function fmt(n){if(typeof n!=='number'||isNaN(n))return'0';return Math.round(n).toLocaleString();}
1163
1237
  function capitalize(s){return s?s.charAt(0).toUpperCase()+s.slice(1):'';}
1164
1238
  const MODEL_NAMES={'opus-4.6':'Claude Opus 4.6','sonnet-4.6':'Claude Sonnet 4.6','gpt-5.4':'GPT 5.4','gpt-5.3-codex':'GPT 5.3 Codex','qwen35':'Qwen 3.5 35B A3B','qwen35-a3b':'Qwen 3.5 35B A3B'};