arkaos 4.13.0 → 4.13.2
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 +1 -1
- package/bin/arka-doctor +15 -1
- package/core/governance/__pycache__/evidence_checks.cpython-313.pyc +0 -0
- package/core/governance/evidence_checks.py +85 -4
- package/core/workflow/__pycache__/design_authorization.cpython-313.pyc +0 -0
- package/core/workflow/__pycache__/frontend_gate.cpython-313.pyc +0 -0
- package/core/workflow/design_authorization.py +106 -0
- package/core/workflow/frontend_gate.py +54 -22
- package/dashboard/app/app.config.ts +2 -2
- package/dashboard/app/assets/css/main.css +285 -13
- package/dashboard/app/components/ArkaConstellation.vue +239 -0
- package/dashboard/app/components/ArkaCountUp.vue +35 -0
- package/dashboard/app/components/ArkaGlowCard.vue +25 -0
- package/dashboard/app/components/ArkaLiveFeed.vue +122 -0
- package/dashboard/app/components/ArkaNavGroupLabel.vue +11 -0
- package/dashboard/app/components/ArkaPageHero.vue +42 -0
- package/dashboard/app/components/ArkaSection.vue +20 -0
- package/dashboard/app/components/ArkaStarfield.vue +3 -0
- package/dashboard/app/components/ArkaStatCard.vue +38 -0
- package/dashboard/app/components/ArkaSystemPill.vue +54 -0
- package/dashboard/app/components/ArkaTrendChart.vue +68 -0
- package/dashboard/app/composables/useCountUp.ts +30 -0
- package/dashboard/app/composables/useDashboard.ts +2 -1
- package/dashboard/app/composables/useTaskStream.ts +39 -0
- package/dashboard/app/layouts/default.vue +11 -2
- package/dashboard/app/pages/design-lab.vue +257 -0
- package/dashboard/app/pages/index.vue +268 -213
- package/dashboard/nuxt.config.ts +21 -0
- package/dashboard/package.json +1 -0
- package/departments/content/skills/video-produce/SKILL.md +9 -1
- package/departments/content/skills/video-setup/SKILL.md +15 -4
- package/installer/core-snapshot.js +44 -20
- package/installer/doctor.js +13 -8
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/start-dashboard.sh +3 -1
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// information the operator actually uses: greeting, today's cost,
|
|
7
|
-
// per-project state, recent incidents, quick actions.
|
|
2
|
+
// Mission Control (Pulse v2). Editorial sci-fi recomposition of the
|
|
3
|
+
// command center: numbered sections, count-up telemetry, agent
|
|
4
|
+
// constellation, live signal feed. Primary gate stays on
|
|
5
|
+
// /api/overview/command-center; section fetches are non-blocking.
|
|
8
6
|
|
|
9
7
|
interface ProjectRow {
|
|
10
8
|
name: string
|
|
@@ -67,15 +65,39 @@ interface CommandCenterPayload {
|
|
|
67
65
|
quick_actions: QuickAction[]
|
|
68
66
|
}
|
|
69
67
|
|
|
68
|
+
interface AgentRow {
|
|
69
|
+
id: string
|
|
70
|
+
name: string
|
|
71
|
+
department: string
|
|
72
|
+
tier: number
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface DeptRow {
|
|
76
|
+
department: string
|
|
77
|
+
agent_count: number
|
|
78
|
+
calls_30d: number
|
|
79
|
+
cost_usd_30d: number | null
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
interface TrendDay {
|
|
83
|
+
date: string
|
|
84
|
+
cost_usd: number
|
|
85
|
+
}
|
|
86
|
+
|
|
70
87
|
const { fetchApi } = useApi()
|
|
71
88
|
|
|
72
89
|
const {
|
|
73
90
|
data,
|
|
74
91
|
status,
|
|
75
92
|
error,
|
|
76
|
-
refresh
|
|
93
|
+
refresh
|
|
77
94
|
} = await fetchApi<CommandCenterPayload>('/api/overview/command-center')
|
|
78
95
|
|
|
96
|
+
// Section fetches — lazy so a slow endpoint never blocks the hero.
|
|
97
|
+
const { data: agentsData } = fetchApi<{ agents: AgentRow[] }>('/api/agents', { lazy: true })
|
|
98
|
+
const { data: deptsData } = fetchApi<{ departments: DeptRow[] }>('/api/departments', { lazy: true })
|
|
99
|
+
const { data: trendData } = fetchApi<{ days: TrendDay[] }>('/api/llm-costs/trend?days=30', { lazy: true })
|
|
100
|
+
|
|
79
101
|
const greetingLabel = computed(() => {
|
|
80
102
|
const name = data.value?.greeting?.name?.trim()
|
|
81
103
|
const language = data.value?.greeting?.language ?? 'en'
|
|
@@ -85,16 +107,18 @@ const greetingLabel = computed(() => {
|
|
|
85
107
|
|
|
86
108
|
const todayCost = computed(() => data.value?.today_cost)
|
|
87
109
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
110
|
+
const trendSeries = computed(() =>
|
|
111
|
+
(trendData.value?.days ?? []).map(d => ({ date: d.date, value: d.cost_usd ?? 0 }))
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
const constellationAgents = computed(() => agentsData.value?.agents ?? [])
|
|
115
|
+
const constellationDepts = computed(() =>
|
|
116
|
+
(deptsData.value?.departments ?? []).map(d => ({ department: d.department, calls_30d: d.calls_30d }))
|
|
117
|
+
)
|
|
94
118
|
|
|
95
119
|
function formatTokens(n: number): string {
|
|
96
120
|
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`
|
|
97
|
-
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}
|
|
121
|
+
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`
|
|
98
122
|
return n.toString()
|
|
99
123
|
}
|
|
100
124
|
|
|
@@ -108,13 +132,13 @@ function statusColor(status: string): 'success' | 'warning' | 'neutral' | 'error
|
|
|
108
132
|
}
|
|
109
133
|
}
|
|
110
134
|
|
|
111
|
-
function commitFreshness(days: number | null): { color: string
|
|
135
|
+
function commitFreshness(days: number | null): { color: string, label: string } {
|
|
112
136
|
if (days === null) return { color: 'text-muted', label: 'no git' }
|
|
113
|
-
if (days === 0) return { color: 'text-
|
|
114
|
-
if (days === 1) return { color: 'text-
|
|
137
|
+
if (days === 0) return { color: 'text-primary', label: 'today' }
|
|
138
|
+
if (days === 1) return { color: 'text-primary', label: '1 day ago' }
|
|
115
139
|
if (days < 7) return { color: 'text-primary', label: `${days} days ago` }
|
|
116
|
-
if (days < 30) return { color: 'text-
|
|
117
|
-
return { color: 'text-
|
|
140
|
+
if (days < 30) return { color: 'text-warning', label: `${days} days ago` }
|
|
141
|
+
return { color: 'text-error', label: `${days} days ago` }
|
|
118
142
|
}
|
|
119
143
|
|
|
120
144
|
function formatIncidentTs(iso: string): string {
|
|
@@ -124,7 +148,7 @@ function formatIncidentTs(iso: string): string {
|
|
|
124
148
|
month: 'short',
|
|
125
149
|
day: 'numeric',
|
|
126
150
|
hour: '2-digit',
|
|
127
|
-
minute: '2-digit'
|
|
151
|
+
minute: '2-digit'
|
|
128
152
|
}).format(new Date(iso))
|
|
129
153
|
} catch {
|
|
130
154
|
return iso
|
|
@@ -146,7 +170,7 @@ function copyCommand(cmd: string) {
|
|
|
146
170
|
<template>
|
|
147
171
|
<UDashboardPanel id="overview">
|
|
148
172
|
<template #header>
|
|
149
|
-
<UDashboardNavbar title="
|
|
173
|
+
<UDashboardNavbar title="Mission Control">
|
|
150
174
|
<template #leading>
|
|
151
175
|
<UDashboardSidebarCollapse />
|
|
152
176
|
</template>
|
|
@@ -166,157 +190,135 @@ function copyCommand(cmd: string) {
|
|
|
166
190
|
<DashboardState
|
|
167
191
|
:status="status"
|
|
168
192
|
:error="error"
|
|
169
|
-
loading-label="Loading
|
|
193
|
+
loading-label="Loading mission control"
|
|
170
194
|
:on-retry="() => refresh()"
|
|
171
195
|
>
|
|
172
|
-
<div class="space-y-
|
|
173
|
-
<!--
|
|
174
|
-
<
|
|
175
|
-
<
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
<
|
|
196
|
+
<div class="mx-auto w-full max-w-6xl space-y-12 py-2">
|
|
197
|
+
<!-- I. STATUS -->
|
|
198
|
+
<div class="space-y-6">
|
|
199
|
+
<ArkaPageHero
|
|
200
|
+
numeral="I"
|
|
201
|
+
label="mission control"
|
|
202
|
+
:title="greetingLabel"
|
|
203
|
+
:subtitle="data?.greeting?.role && data?.greeting?.company
|
|
204
|
+
? `${data.greeting.role} @ ${data.greeting.company} — status of every agent, every memory, every signal.`
|
|
205
|
+
: 'Status of every agent, every memory, every signal.'"
|
|
206
|
+
>
|
|
207
|
+
<template #stats>
|
|
208
|
+
<div class="grid grid-cols-2 gap-3 pt-4 lg:grid-cols-4">
|
|
209
|
+
<ArkaStatCard
|
|
210
|
+
label="today’s cost"
|
|
211
|
+
:value="todayCost?.total_usd ?? null"
|
|
212
|
+
format="currency"
|
|
213
|
+
:decimals="2"
|
|
214
|
+
accent
|
|
215
|
+
/>
|
|
216
|
+
<ArkaStatCard
|
|
217
|
+
label="calls"
|
|
218
|
+
:value="todayCost?.call_count ?? null"
|
|
219
|
+
/>
|
|
220
|
+
<ArkaStatCard
|
|
221
|
+
label="tokens in / out"
|
|
222
|
+
:value="(todayCost?.tokens_in ?? 0) + (todayCost?.tokens_out ?? 0)"
|
|
223
|
+
format="tokens"
|
|
224
|
+
:hint="todayCost ? `${formatTokens(todayCost.tokens_in ?? 0)} in · ${formatTokens(todayCost.tokens_out ?? 0)} out` : ''"
|
|
225
|
+
/>
|
|
226
|
+
<ArkaStatCard
|
|
227
|
+
label="cache hit rate"
|
|
228
|
+
:value="todayCost?.cache_hit_rate ?? null"
|
|
229
|
+
format="percent"
|
|
230
|
+
/>
|
|
193
231
|
</div>
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
Calls
|
|
197
|
-
</p>
|
|
198
|
-
<p class="text-2xl font-bold">{{ todayCost.call_count }}</p>
|
|
199
|
-
</div>
|
|
200
|
-
<div>
|
|
201
|
-
<p class="text-xs font-semibold text-muted uppercase tracking-wider">
|
|
202
|
-
Cache
|
|
203
|
-
</p>
|
|
204
|
-
<p class="text-2xl font-bold">
|
|
205
|
-
{{ (todayCost.cache_hit_rate * 100).toFixed(0) }}%
|
|
206
|
-
</p>
|
|
207
|
-
</div>
|
|
208
|
-
</div>
|
|
209
|
-
</div>
|
|
210
|
-
</UCard>
|
|
232
|
+
</template>
|
|
233
|
+
</ArkaPageHero>
|
|
211
234
|
|
|
212
|
-
|
|
213
|
-
<AgentSuggestionsCard class="mb-6" />
|
|
235
|
+
<div class="arka-pulse-line" aria-hidden="true" />
|
|
214
236
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
:
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
>
|
|
228
|
-
<div class="space-y-2">
|
|
229
|
-
<div
|
|
230
|
-
v-for="(d, idx) in data?.top_departments_30d"
|
|
231
|
-
:key="d.department"
|
|
232
|
-
class="rounded-lg border border-default p-3 flex items-center gap-3"
|
|
233
|
-
>
|
|
234
|
-
<span class="text-xs font-mono font-semibold text-muted w-6">#{{ idx + 1 }}</span>
|
|
235
|
-
<span class="flex-1 font-semibold capitalize">{{ d.department }}</span>
|
|
236
|
-
<span class="text-xs font-mono text-muted">{{ d.calls }} calls</span>
|
|
237
|
-
<span class="text-sm font-mono font-semibold">
|
|
238
|
-
{{ d.cost_usd === null ? '—' : `$${d.cost_usd.toFixed(2)}` }}
|
|
239
|
-
</span>
|
|
240
|
-
</div>
|
|
241
|
-
</div>
|
|
242
|
-
</DashboardState>
|
|
243
|
-
</div>
|
|
237
|
+
<ArkaGlowCard v-if="trendSeries.length" :padded="false" class="px-2 pt-4 pb-1">
|
|
238
|
+
<div class="flex items-center justify-between px-3 pb-2">
|
|
239
|
+
<span class="arka-eyebrow">cumulative spend · 30d</span>
|
|
240
|
+
<span class="arka-data text-xs text-muted">
|
|
241
|
+
${{ trendSeries.reduce((s, d) => s + d.value, 0).toFixed(2) }} total
|
|
242
|
+
</span>
|
|
243
|
+
</div>
|
|
244
|
+
<ClientOnly>
|
|
245
|
+
<ArkaTrendChart :series="trendSeries" :height="150" />
|
|
246
|
+
</ClientOnly>
|
|
247
|
+
</ArkaGlowCard>
|
|
248
|
+
</div>
|
|
244
249
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
<div class="min-w-0">
|
|
265
|
-
<p class="text-sm font-semibold truncate">{{ p.name }}</p>
|
|
266
|
-
<p class="text-xs text-muted truncate">{{ p.title || '—' }}</p>
|
|
267
|
-
</div>
|
|
268
|
-
<div class="flex items-center gap-2 shrink-0">
|
|
269
|
-
<UBadge
|
|
270
|
-
v-if="p.mbti"
|
|
271
|
-
:label="p.mbti"
|
|
272
|
-
variant="subtle"
|
|
273
|
-
size="xs"
|
|
274
|
-
/>
|
|
275
|
-
<UBadge
|
|
276
|
-
v-if="p.source_store === 'obsidian'"
|
|
277
|
-
icon="i-lucide-file-text"
|
|
278
|
-
label="Obsidian"
|
|
279
|
-
color="primary"
|
|
280
|
-
variant="soft"
|
|
281
|
-
size="xs"
|
|
282
|
-
/>
|
|
283
|
-
</div>
|
|
284
|
-
</div>
|
|
285
|
-
</NuxtLink>
|
|
250
|
+
<!-- II. AGENT CONSTELLATION -->
|
|
251
|
+
<ArkaSection numeral="II" label="agent constellation">
|
|
252
|
+
<template #actions>
|
|
253
|
+
<NuxtLink to="/agents" class="arka-data text-xs text-muted transition-colors hover:text-primary">
|
|
254
|
+
open agents →
|
|
255
|
+
</NuxtLink>
|
|
256
|
+
</template>
|
|
257
|
+
<ArkaGlowCard :padded="false">
|
|
258
|
+
<ClientOnly>
|
|
259
|
+
<ArkaConstellation
|
|
260
|
+
v-if="constellationAgents.length"
|
|
261
|
+
:agents="constellationAgents"
|
|
262
|
+
:departments="constellationDepts"
|
|
263
|
+
:height="380"
|
|
264
|
+
/>
|
|
265
|
+
<div v-else class="flex h-64 items-center justify-center">
|
|
266
|
+
<p class="arka-data text-xs text-muted">
|
|
267
|
+
mapping the constellation…
|
|
268
|
+
</p>
|
|
286
269
|
</div>
|
|
287
|
-
</
|
|
270
|
+
</ClientOnly>
|
|
271
|
+
</ArkaGlowCard>
|
|
272
|
+
<div v-if="data?.top_departments_30d?.length" class="flex flex-wrap gap-2">
|
|
273
|
+
<NuxtLink
|
|
274
|
+
v-for="(d, idx) in data.top_departments_30d"
|
|
275
|
+
:key="d.department"
|
|
276
|
+
:to="`/departments/${d.department}`"
|
|
277
|
+
class="flex items-center gap-2 rounded-full border border-default bg-elevated px-3 py-1.5 transition-colors hover:border-primary/40"
|
|
278
|
+
>
|
|
279
|
+
<span class="arka-data text-[10px] text-muted">#{{ idx + 1 }}</span>
|
|
280
|
+
<span class="text-xs font-medium capitalize">{{ d.department }}</span>
|
|
281
|
+
<span class="arka-data text-[10px] text-muted">{{ d.calls }} calls</span>
|
|
282
|
+
<span class="arka-data text-[10px]" :class="d.cost_usd === null ? 'text-muted' : 'text-primary'">
|
|
283
|
+
{{ d.cost_usd === null ? '—' : `$${d.cost_usd.toFixed(2)}` }}
|
|
284
|
+
</span>
|
|
285
|
+
</NuxtLink>
|
|
288
286
|
</div>
|
|
289
|
-
</
|
|
287
|
+
</ArkaSection>
|
|
290
288
|
|
|
291
|
-
<!--
|
|
292
|
-
<
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
<
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
289
|
+
<!-- III. LIVE FEED -->
|
|
290
|
+
<ArkaSection numeral="III" label="live feed">
|
|
291
|
+
<template #actions>
|
|
292
|
+
<span class="flex items-center gap-2">
|
|
293
|
+
<span class="arka-live-dot" />
|
|
294
|
+
<span class="arka-data text-[10px] text-muted uppercase">live</span>
|
|
295
|
+
</span>
|
|
296
|
+
</template>
|
|
297
|
+
<ArkaLiveFeed />
|
|
298
|
+
</ArkaSection>
|
|
299
|
+
|
|
300
|
+
<!-- IV. PROJECTS & ACTIONS -->
|
|
301
|
+
<ArkaSection numeral="IV" label="projects & actions">
|
|
302
|
+
<AgentSuggestionsCard />
|
|
303
|
+
<div class="grid grid-cols-1 gap-6 lg:grid-cols-[2fr_1fr]">
|
|
304
|
+
<div class="space-y-2">
|
|
305
|
+
<DashboardState
|
|
306
|
+
:status="status"
|
|
307
|
+
:empty="!data?.projects?.length"
|
|
308
|
+
empty-title="No projects discovered yet"
|
|
309
|
+
empty-description="Add your project directories in Settings → Projects."
|
|
310
|
+
empty-icon="i-lucide-folder-open"
|
|
311
|
+
>
|
|
312
|
+
<ArkaGlowCard
|
|
312
313
|
v-for="p in data?.projects"
|
|
313
314
|
:key="p.name"
|
|
314
|
-
|
|
315
|
+
interactive
|
|
316
|
+
class="mb-2"
|
|
315
317
|
>
|
|
316
318
|
<div class="flex items-start justify-between gap-3">
|
|
317
319
|
<div class="min-w-0 flex-1">
|
|
318
|
-
<div class="flex items-center gap-2
|
|
319
|
-
<span class="text-sm font-semibold
|
|
320
|
+
<div class="mb-1 flex items-center gap-2">
|
|
321
|
+
<span class="truncate text-sm font-semibold">{{ p.name }}</span>
|
|
320
322
|
<UBadge
|
|
321
323
|
v-if="p.status"
|
|
322
324
|
:label="p.status"
|
|
@@ -332,8 +334,10 @@ function copyCommand(cmd: string) {
|
|
|
332
334
|
size="xs"
|
|
333
335
|
/>
|
|
334
336
|
</div>
|
|
335
|
-
<p class="text-xs text-muted
|
|
336
|
-
|
|
337
|
+
<p class="arka-data truncate text-xs text-muted">
|
|
338
|
+
{{ p.path }}
|
|
339
|
+
</p>
|
|
340
|
+
<div class="mt-2 flex flex-wrap items-center gap-2">
|
|
337
341
|
<UBadge
|
|
338
342
|
v-for="s in p.stack"
|
|
339
343
|
:key="s"
|
|
@@ -344,75 +348,126 @@ function copyCommand(cmd: string) {
|
|
|
344
348
|
</div>
|
|
345
349
|
</div>
|
|
346
350
|
<span
|
|
347
|
-
class="
|
|
351
|
+
class="arka-data shrink-0 text-xs"
|
|
348
352
|
:class="commitFreshness(p.last_commit_days).color"
|
|
349
353
|
>
|
|
350
354
|
{{ commitFreshness(p.last_commit_days).label }}
|
|
351
355
|
</span>
|
|
352
356
|
</div>
|
|
353
|
-
</
|
|
354
|
-
</
|
|
355
|
-
</
|
|
356
|
-
</div>
|
|
357
|
+
</ArkaGlowCard>
|
|
358
|
+
</DashboardState>
|
|
359
|
+
</div>
|
|
357
360
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
<div class="space-y-2">
|
|
372
|
-
<div
|
|
373
|
-
v-for="(i, idx) in data?.recent_incidents"
|
|
374
|
-
:key="idx"
|
|
375
|
-
class="rounded-lg border border-default p-3"
|
|
361
|
+
<div class="space-y-6">
|
|
362
|
+
<div>
|
|
363
|
+
<p class="arka-eyebrow mb-3">
|
|
364
|
+
quick launch
|
|
365
|
+
</p>
|
|
366
|
+
<div class="space-y-1.5">
|
|
367
|
+
<button
|
|
368
|
+
v-for="a in data?.quick_actions"
|
|
369
|
+
:key="a.command"
|
|
370
|
+
type="button"
|
|
371
|
+
class="arka-glow-card w-full p-3 text-left"
|
|
372
|
+
data-interactive="true"
|
|
373
|
+
@click="copyCommand(a.command)"
|
|
376
374
|
>
|
|
377
|
-
<div class="flex items-center gap-2
|
|
378
|
-
<
|
|
379
|
-
|
|
380
|
-
:color="i.kind === 'bypass' ? 'warning' : 'error'"
|
|
381
|
-
variant="subtle"
|
|
382
|
-
size="xs"
|
|
383
|
-
/>
|
|
384
|
-
<span class="text-xs text-muted">{{ formatIncidentTs(i.ts) }}</span>
|
|
375
|
+
<div class="flex items-center gap-2">
|
|
376
|
+
<code class="arka-data text-sm font-semibold text-primary">{{ a.command }}</code>
|
|
377
|
+
<UIcon name="i-lucide-clipboard" class="ml-auto size-3 text-muted" />
|
|
385
378
|
</div>
|
|
386
|
-
<p class="text-xs
|
|
387
|
-
{{
|
|
379
|
+
<p class="mt-1 text-xs text-muted">
|
|
380
|
+
{{ a.description }}
|
|
388
381
|
</p>
|
|
389
|
-
</
|
|
382
|
+
</button>
|
|
390
383
|
</div>
|
|
391
|
-
</
|
|
392
|
-
</div>
|
|
384
|
+
</div>
|
|
393
385
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
@click="copyCommand(a.command)"
|
|
386
|
+
<div>
|
|
387
|
+
<p class="arka-eyebrow mb-3">
|
|
388
|
+
recent incidents
|
|
389
|
+
</p>
|
|
390
|
+
<DashboardState
|
|
391
|
+
:status="status"
|
|
392
|
+
:empty="!data?.recent_incidents?.length"
|
|
393
|
+
empty-title="No incidents"
|
|
394
|
+
empty-description="Bypass uses and flow blocks show up here."
|
|
395
|
+
empty-icon="i-lucide-shield-check"
|
|
405
396
|
>
|
|
406
|
-
<div class="
|
|
407
|
-
<
|
|
408
|
-
|
|
397
|
+
<div class="space-y-1.5">
|
|
398
|
+
<div
|
|
399
|
+
v-for="(i, idx) in data?.recent_incidents"
|
|
400
|
+
:key="idx"
|
|
401
|
+
class="rounded-lg border border-default p-3"
|
|
402
|
+
>
|
|
403
|
+
<div class="mb-1 flex items-center gap-2">
|
|
404
|
+
<UBadge
|
|
405
|
+
:label="i.kind"
|
|
406
|
+
:color="i.kind === 'bypass' ? 'warning' : 'error'"
|
|
407
|
+
variant="subtle"
|
|
408
|
+
size="xs"
|
|
409
|
+
/>
|
|
410
|
+
<span class="arka-data text-xs text-muted">{{ formatIncidentTs(i.ts) }}</span>
|
|
411
|
+
</div>
|
|
412
|
+
<p class="arka-data truncate text-xs text-muted" :title="i.reason">
|
|
413
|
+
{{ i.tool }} — {{ i.reason }}
|
|
414
|
+
</p>
|
|
415
|
+
</div>
|
|
409
416
|
</div>
|
|
410
|
-
|
|
411
|
-
|
|
417
|
+
</DashboardState>
|
|
418
|
+
</div>
|
|
419
|
+
|
|
420
|
+
<div>
|
|
421
|
+
<p class="arka-eyebrow mb-3">
|
|
422
|
+
recent personas
|
|
423
|
+
</p>
|
|
424
|
+
<DashboardState
|
|
425
|
+
:status="status"
|
|
426
|
+
:empty="!data?.recent_personas?.length"
|
|
427
|
+
empty-title="No personas yet"
|
|
428
|
+
empty-description="Create one from /personas → New Persona."
|
|
429
|
+
empty-icon="i-lucide-user-plus"
|
|
430
|
+
>
|
|
431
|
+
<div class="space-y-1.5">
|
|
432
|
+
<NuxtLink
|
|
433
|
+
v-for="p in data?.recent_personas"
|
|
434
|
+
:key="p.id"
|
|
435
|
+
:to="`/personas/${p.id}`"
|
|
436
|
+
class="block rounded-lg border border-default p-3 transition-colors hover:border-primary/40"
|
|
437
|
+
>
|
|
438
|
+
<div class="flex items-center justify-between gap-3">
|
|
439
|
+
<div class="min-w-0">
|
|
440
|
+
<p class="truncate text-sm font-semibold">
|
|
441
|
+
{{ p.name }}
|
|
442
|
+
</p>
|
|
443
|
+
<p class="truncate text-xs text-muted">
|
|
444
|
+
{{ p.title || '—' }}
|
|
445
|
+
</p>
|
|
446
|
+
</div>
|
|
447
|
+
<div class="flex shrink-0 items-center gap-2">
|
|
448
|
+
<UBadge
|
|
449
|
+
v-if="p.mbti"
|
|
450
|
+
:label="p.mbti"
|
|
451
|
+
variant="subtle"
|
|
452
|
+
size="xs"
|
|
453
|
+
/>
|
|
454
|
+
<UBadge
|
|
455
|
+
v-if="p.source_store === 'obsidian'"
|
|
456
|
+
icon="i-lucide-file-text"
|
|
457
|
+
label="Obsidian"
|
|
458
|
+
color="primary"
|
|
459
|
+
variant="soft"
|
|
460
|
+
size="xs"
|
|
461
|
+
/>
|
|
462
|
+
</div>
|
|
463
|
+
</div>
|
|
464
|
+
</NuxtLink>
|
|
465
|
+
</div>
|
|
466
|
+
</DashboardState>
|
|
412
467
|
</div>
|
|
413
468
|
</div>
|
|
414
469
|
</div>
|
|
415
|
-
</
|
|
470
|
+
</ArkaSection>
|
|
416
471
|
</div>
|
|
417
472
|
</DashboardState>
|
|
418
473
|
</template>
|
package/dashboard/nuxt.config.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
export default defineNuxtConfig({
|
|
3
3
|
modules: [
|
|
4
4
|
'@nuxt/eslint',
|
|
5
|
+
'@nuxt/fonts',
|
|
5
6
|
'@nuxt/ui',
|
|
6
7
|
'@vueuse/nuxt'
|
|
7
8
|
],
|
|
@@ -12,8 +13,20 @@ export default defineNuxtConfig({
|
|
|
12
13
|
enabled: true
|
|
13
14
|
},
|
|
14
15
|
|
|
16
|
+
app: {
|
|
17
|
+
pageTransition: {
|
|
18
|
+
name: 'arka-page',
|
|
19
|
+
mode: 'out-in'
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
|
|
15
23
|
css: ['~/assets/css/main.css'],
|
|
16
24
|
|
|
25
|
+
colorMode: {
|
|
26
|
+
preference: 'dark',
|
|
27
|
+
fallback: 'dark'
|
|
28
|
+
},
|
|
29
|
+
|
|
17
30
|
runtimeConfig: {
|
|
18
31
|
public: {
|
|
19
32
|
apiBase: 'http://localhost:3334'
|
|
@@ -35,5 +48,13 @@ export default defineNuxtConfig({
|
|
|
35
48
|
braceStyle: '1tbs'
|
|
36
49
|
}
|
|
37
50
|
}
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
fonts: {
|
|
54
|
+
families: [
|
|
55
|
+
// Explicit entry guarantees the italic axis (Instrument Serif ships
|
|
56
|
+
// 400 normal+italic only); the other families auto-resolve from @theme.
|
|
57
|
+
{ name: 'Instrument Serif', provider: 'google', weights: [400], styles: ['normal', 'italic'] }
|
|
58
|
+
]
|
|
38
59
|
}
|
|
39
60
|
})
|