arkaos 3.39.0 → 3.41.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.39.0
1
+ 3.41.0
@@ -0,0 +1,165 @@
1
+ <script setup lang="ts">
2
+ // PR92c v3.41.0 — first-visit onboarding tour.
3
+ //
4
+ // One-shot modal that shows up on the home page until the operator
5
+ // dismisses it. Walks through Agents → Personas → Workflows → Budget.
6
+ // Dismissal persists in localStorage as `arkaos_onboarding_dismissed`.
7
+
8
+ const open = ref(false)
9
+ const step = ref(0)
10
+ const router = useRouter()
11
+ const route = useRoute()
12
+
13
+ const STORAGE_KEY = 'arkaos_onboarding_dismissed'
14
+
15
+ interface TourStep {
16
+ icon: string
17
+ title: string
18
+ body: string
19
+ cta?: { label: string, to: string }
20
+ }
21
+
22
+ const steps: TourStep[] = [
23
+ {
24
+ icon: 'i-lucide-sparkles',
25
+ title: 'Welcome to ArkaOS',
26
+ body: 'A 4-minute tour of where to start. Press Esc anytime to skip — you can replay this from Settings.',
27
+ },
28
+ {
29
+ icon: 'i-lucide-users',
30
+ title: 'Agents',
31
+ body: 'Your specialist team. Browse the table, click a row for full detail (DNA, expertise, history). Create new ones with the AI draft on /agents/new.',
32
+ cta: { label: 'Open /agents', to: '/agents' },
33
+ },
34
+ {
35
+ icon: 'i-lucide-user-plus',
36
+ title: 'Personas',
37
+ body: 'Behavioural profiles of real people (or archetypes) that seed your agents. Import from .md files / URLs, export as ZIP, clone to agents.',
38
+ cta: { label: 'Open /personas', to: '/personas' },
39
+ },
40
+ {
41
+ icon: 'i-lucide-workflow',
42
+ title: 'Workflows',
43
+ body: 'YAML-defined orchestrations under departments/. Click a workflow for its phase flow, raw YAML, and recent runs.',
44
+ cta: { label: 'Open /workflows', to: '/workflows' },
45
+ },
46
+ {
47
+ icon: 'i-lucide-wallet',
48
+ title: 'Budget',
49
+ body: 'Real LLM spend by provider/model/category, daily trend chart (7/14/30d), CSV export. Powered by PR47 telemetry.',
50
+ cta: { label: 'Open /budget', to: '/budget' },
51
+ },
52
+ {
53
+ icon: 'i-lucide-keyboard',
54
+ title: 'Power shortcuts',
55
+ body: 'Press ? anywhere for the full keymap. Try / for search, g a for agents, g p for personas.',
56
+ },
57
+ ]
58
+
59
+ onMounted(() => {
60
+ if (typeof window === 'undefined') return
61
+ if (window.localStorage.getItem(STORAGE_KEY) === '1') return
62
+ // Only auto-open on the home route — operators clicking around shouldn't
63
+ // be interrupted.
64
+ if (route.path !== '/') return
65
+ open.value = true
66
+ })
67
+
68
+ function next() {
69
+ if (step.value < steps.length - 1) {
70
+ step.value += 1
71
+ } else {
72
+ dismiss()
73
+ }
74
+ }
75
+
76
+ function back() {
77
+ if (step.value > 0) step.value -= 1
78
+ }
79
+
80
+ function dismiss() {
81
+ open.value = false
82
+ if (typeof window !== 'undefined') {
83
+ window.localStorage.setItem(STORAGE_KEY, '1')
84
+ }
85
+ }
86
+
87
+ function navigateAndDismiss(to: string) {
88
+ dismiss()
89
+ router.push(to)
90
+ }
91
+
92
+ const current = computed(() => steps[step.value])
93
+ const progress = computed(() => Math.round(((step.value + 1) / steps.length) * 100))
94
+ </script>
95
+
96
+ <template>
97
+ <UModal
98
+ v-model:open="open"
99
+ :ui="{ content: 'max-w-lg' }"
100
+ title="Welcome"
101
+ >
102
+ <template #content>
103
+ <UCard>
104
+ <template #header>
105
+ <div class="flex items-center justify-between gap-3">
106
+ <div class="flex items-center gap-3">
107
+ <UIcon :name="current.icon" class="size-6 text-primary" />
108
+ <div>
109
+ <h2 class="text-lg font-bold">{{ current.title }}</h2>
110
+ <p class="text-xs text-muted mt-0.5">
111
+ Step {{ step + 1 }} of {{ steps.length }}
112
+ </p>
113
+ </div>
114
+ </div>
115
+ <UButton icon="i-lucide-x" variant="ghost" size="sm" aria-label="Skip" @click="dismiss" />
116
+ </div>
117
+ </template>
118
+
119
+ <div class="space-y-4">
120
+ <p class="text-sm">{{ current.body }}</p>
121
+ <UButton
122
+ v-if="current.cta"
123
+ :label="current.cta.label"
124
+ :icon="current.icon"
125
+ variant="soft"
126
+ color="primary"
127
+ @click="navigateAndDismiss(current.cta!.to)"
128
+ />
129
+ <div class="h-1.5 rounded-full bg-elevated/40 overflow-hidden">
130
+ <div
131
+ class="h-1.5 rounded-full bg-primary transition-all duration-200"
132
+ :style="{ width: `${progress}%` }"
133
+ />
134
+ </div>
135
+ </div>
136
+
137
+ <template #footer>
138
+ <div class="flex items-center justify-between gap-2 text-xs">
139
+ <UButton
140
+ label="Don't show again"
141
+ variant="ghost"
142
+ size="xs"
143
+ @click="dismiss"
144
+ />
145
+ <div class="flex items-center gap-2">
146
+ <UButton
147
+ v-if="step > 0"
148
+ label="Back"
149
+ variant="ghost"
150
+ size="sm"
151
+ @click="back"
152
+ />
153
+ <UButton
154
+ :label="step === steps.length - 1 ? 'Finish' : 'Next'"
155
+ icon="i-lucide-arrow-right"
156
+ size="sm"
157
+ @click="next"
158
+ />
159
+ </div>
160
+ </div>
161
+ </template>
162
+ </UCard>
163
+ </template>
164
+ </UModal>
165
+ </template>
@@ -158,5 +158,6 @@ const links = [[{
158
158
  <slot />
159
159
  <KeyboardShortcutsHelp />
160
160
  <GlobalSearch />
161
+ <OnboardingTour />
161
162
  </UDashboardGroup>
162
163
  </template>
@@ -69,9 +69,13 @@ async function refreshAll() {
69
69
  await Promise.all([refresh(), refreshActivity()])
70
70
  }
71
71
 
72
- const search = ref('')
73
- const departmentFilter = ref('all')
74
- const tierFilter = ref('all')
72
+ // PR92b v3.40.0 — initial values come from ?q=...&dept=...&tier=...
73
+ // so /agents links can deep-link to a filtered view.
74
+ const route = useRoute()
75
+ const router = useRouter()
76
+ const search = ref(String(route.query.q ?? ''))
77
+ const departmentFilter = ref(String(route.query.dept ?? 'all'))
78
+ const tierFilter = ref(String(route.query.tier ?? 'all'))
75
79
  const page = ref(1)
76
80
  const pageSize = 15
77
81
 
@@ -92,8 +96,13 @@ const tierOptions = [
92
96
  ]
93
97
 
94
98
  // PR87a v3.19.0 — DNA filters (DISC primary + MBTI group).
95
- const discFilter = ref<'all' | 'D' | 'I' | 'S' | 'C'>('all')
96
- const mbtiGroupFilter = ref<'all' | 'analysts' | 'diplomats' | 'sentinels' | 'explorers'>('all')
99
+ // PR92b v3.40.0 seed from URL query.
100
+ const discFilter = ref<'all' | 'D' | 'I' | 'S' | 'C'>(
101
+ (route.query.disc as any) ?? 'all',
102
+ )
103
+ const mbtiGroupFilter = ref<'all' | 'analysts' | 'diplomats' | 'sentinels' | 'explorers'>(
104
+ (route.query.mbti as any) ?? 'all',
105
+ )
97
106
 
98
107
  const discOptions = [
99
108
  { label: 'All DISC', value: 'all' },
@@ -164,6 +173,23 @@ const paginatedAgents = computed(() => {
164
173
 
165
174
  const totalPages = computed(() => Math.max(1, Math.ceil(totalFiltered.value / pageSize)))
166
175
 
176
+ // PR92b v3.40.0 — push filter state to URL so deep-links survive reload
177
+ // and the browser back/forward buttons work as expected.
178
+ watch(
179
+ [search, departmentFilter, tierFilter, discFilter, mbtiGroupFilter, favoritesOnly],
180
+ () => {
181
+ const query: Record<string, string> = {}
182
+ if (search.value.trim()) query.q = search.value.trim()
183
+ if (departmentFilter.value !== 'all') query.dept = departmentFilter.value
184
+ if (tierFilter.value !== 'all') query.tier = tierFilter.value
185
+ if (discFilter.value !== 'all') query.disc = discFilter.value
186
+ if (mbtiGroupFilter.value !== 'all') query.mbti = mbtiGroupFilter.value
187
+ if (favoritesOnly.value) query.fav = '1'
188
+ router.replace({ query })
189
+ },
190
+ { flush: 'post' },
191
+ )
192
+
167
193
  watch([search, departmentFilter, tierFilter, discFilter, mbtiGroupFilter], () => {
168
194
  page.value = 1
169
195
  })
@@ -200,9 +226,10 @@ function goToAgent(id: string) {
200
226
  }
201
227
 
202
228
  // PR86a v3.15.0 — favorites.
229
+ // PR92b v3.40.0 — favoritesOnly persists in URL (`?fav=1`).
203
230
  const favs = useFavorites()
204
231
  await favs.load()
205
- const favoritesOnly = ref(false)
232
+ const favoritesOnly = ref(route.query.fav === '1')
206
233
 
207
234
  // PR83b v3.4.0 — bulk selection + delete.
208
235
  // PR84b v3.8.0 — bulk move department.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkaos",
3
- "version": "3.39.0",
3
+ "version": "3.41.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.39.0"
3
+ version = "3.41.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"}