arkaos 3.21.0 → 3.22.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/VERSION CHANGED
@@ -1 +1 @@
1
- 3.21.0
1
+ 3.22.0
@@ -0,0 +1,61 @@
1
+ <script setup lang="ts">
2
+ // PR87d v3.22.0 — compact stats card mounted at the bottom of the
3
+ // sidebar. Polls /api/sidebar-stats every 60s.
4
+
5
+ interface SidebarStats {
6
+ agents: number
7
+ personas: number
8
+ departments: number
9
+ today_cost_usd: number | null
10
+ today_calls: number
11
+ }
12
+
13
+ const { fetchApi } = useApi()
14
+ const { data, refresh } = fetchApi<SidebarStats>('/api/sidebar-stats')
15
+
16
+ let timer: ReturnType<typeof setInterval> | null = null
17
+ onMounted(() => {
18
+ timer = setInterval(() => { refresh() }, 60_000)
19
+ })
20
+ onBeforeUnmount(() => {
21
+ if (timer) clearInterval(timer)
22
+ })
23
+
24
+ function formatCost(cost: number | null): string {
25
+ if (cost === null || cost === undefined) return '—'
26
+ if (cost < 0.01) return '<$0.01'
27
+ if (cost < 1) return `$${cost.toFixed(3)}`
28
+ return `$${cost.toFixed(2)}`
29
+ }
30
+ </script>
31
+
32
+ <template>
33
+ <div
34
+ v-if="data"
35
+ class="rounded-lg border border-default bg-elevated/20 p-3 mx-2 mb-2 text-xs space-y-1.5"
36
+ aria-label="Workspace quick stats"
37
+ >
38
+ <div class="flex items-center justify-between">
39
+ <span class="text-muted">Agents</span>
40
+ <span class="font-mono font-semibold">{{ data.agents }}</span>
41
+ </div>
42
+ <div class="flex items-center justify-between">
43
+ <span class="text-muted">Personas</span>
44
+ <span class="font-mono font-semibold">{{ data.personas }}</span>
45
+ </div>
46
+ <div class="flex items-center justify-between">
47
+ <span class="text-muted">Departments</span>
48
+ <span class="font-mono font-semibold">{{ data.departments }}</span>
49
+ </div>
50
+ <div class="border-t border-default/60 mt-2 pt-1.5 flex items-center justify-between">
51
+ <span class="text-muted">Today</span>
52
+ <span class="font-mono font-semibold text-primary">
53
+ {{ formatCost(data.today_cost_usd) }}
54
+ </span>
55
+ </div>
56
+ <div class="flex items-center justify-between text-[10px] text-muted/70">
57
+ <span>{{ data.today_calls }} call{{ data.today_calls === 1 ? '' : 's' }}</span>
58
+ <span>auto · 60s</span>
59
+ </div>
60
+ </div>
61
+ </template>
@@ -121,12 +121,15 @@ const links = [[{
121
121
  popover
122
122
  />
123
123
 
124
+ <!-- PR87d v3.22.0 — quick stats widget above the bottom nav. -->
125
+ <SidebarStatsWidget v-if="!collapsed" class="mt-auto" />
126
+
124
127
  <UNavigationMenu
125
128
  :collapsed="collapsed"
126
129
  :items="links[1]"
127
130
  orientation="vertical"
128
131
  tooltip
129
- class="mt-auto"
132
+ :class="collapsed ? 'mt-auto' : ''"
130
133
  />
131
134
  </template>
132
135
  </UDashboardSidebar>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkaos",
3
- "version": "3.21.0",
3
+ "version": "3.22.0",
4
4
  "description": "The Operating System for AI Agent Teams",
5
5
  "type": "module",
6
6
  "bin": {
package/pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "arkaos-core"
3
- version = "3.21.0"
3
+ version = "3.22.0"
4
4
  description = "Core engine for ArkaOS — The Operating System for AI Agent Teams"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -1387,6 +1387,43 @@ def agent_export_to_vault(agent_id: str):
1387
1387
  return {"exported": True, "path": str(res.path), "vault_path": str(res.vault_path)}
1388
1388
 
1389
1389
 
1390
+ # --- Sidebar stats widget (PR87d v3.22.0) ---
1391
+
1392
+ @app.get("/api/sidebar-stats")
1393
+ def sidebar_stats():
1394
+ """Compact payload for the sidebar status widget.
1395
+
1396
+ Returns counts the widget actually displays — agents, personas,
1397
+ departments, today's spend. Cheaper than /api/overview/command-center
1398
+ because it skips project scanning, incidents, and quick actions.
1399
+ """
1400
+ agents = _load_agents()
1401
+ departments = {a.get("department") for a in agents if a.get("department")}
1402
+ persona_count = 0
1403
+ mgr = _get_persona_manager()
1404
+ if mgr:
1405
+ try:
1406
+ persona_count = len(mgr.list() or [])
1407
+ except Exception:
1408
+ persona_count = 0
1409
+ today_cost_usd: float | None = None
1410
+ call_count = 0
1411
+ try:
1412
+ from core.runtime.llm_cost_telemetry import summarise
1413
+ s = summarise(period="today")
1414
+ today_cost_usd = s.total_cost_usd
1415
+ call_count = s.call_count
1416
+ except Exception:
1417
+ pass
1418
+ return {
1419
+ "agents": len(agents),
1420
+ "personas": persona_count,
1421
+ "departments": len(departments),
1422
+ "today_cost_usd": today_cost_usd,
1423
+ "today_calls": call_count,
1424
+ }
1425
+
1426
+
1390
1427
  # --- Favorites (PR86a v3.15.0) ---
1391
1428
 
1392
1429
  @app.get("/api/favorites")