arkaos 3.46.0 → 3.48.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.46.0
1
+ 3.48.0
@@ -54,20 +54,30 @@ function kindColor(kind: string): string {
54
54
  </UButton>
55
55
 
56
56
  <template #content>
57
- <div class="p-2 border-b border-default flex items-center justify-between">
57
+ <div class="p-2 border-b border-default flex items-center justify-between gap-2">
58
58
  <div>
59
59
  <p class="text-sm font-semibold">Recent activity</p>
60
60
  <p class="text-xs text-muted">
61
- Last {{ Math.min(feed.events.value.length, 50) }} event{{ feed.events.value.length === 1 ? '' : 's' }}
61
+ {{ feed.unreadCount.value }} unread ·
62
+ {{ feed.events.value.length }} total
62
63
  </p>
63
64
  </div>
64
- <UButton
65
- v-if="feed.events.value.length > 0"
66
- label="Clear"
67
- variant="ghost"
68
- size="xs"
69
- @click="feed.clear()"
70
- />
65
+ <div class="flex items-center gap-1">
66
+ <UButton
67
+ v-if="feed.unreadCount.value > 0"
68
+ label="Mark all read"
69
+ variant="ghost"
70
+ size="xs"
71
+ @click="feed.markAllRead()"
72
+ />
73
+ <UButton
74
+ v-if="feed.events.value.length > 0"
75
+ label="Clear"
76
+ variant="ghost"
77
+ size="xs"
78
+ @click="feed.clear()"
79
+ />
80
+ </div>
71
81
  </div>
72
82
  <div class="max-h-80 overflow-y-auto">
73
83
  <p
@@ -81,7 +91,9 @@ function kindColor(kind: string): string {
81
91
  <li
82
92
  v-for="ev in feed.events.value"
83
93
  :key="ev.id"
84
- class="px-3 py-2 hover:bg-elevated/40 transition-colors group"
94
+ class="px-3 py-2 hover:bg-elevated/40 transition-colors group cursor-pointer"
95
+ :class="{ 'bg-primary/5': !ev.read }"
96
+ @click="feed.markRead(ev.id)"
85
97
  >
86
98
  <component
87
99
  :is="ev.to ? 'NuxtLink' : 'div'"
@@ -93,7 +105,16 @@ function kindColor(kind: string): string {
93
105
  :class="['size-4 shrink-0 mt-0.5', kindColor(ev.kind)]"
94
106
  />
95
107
  <div class="flex-1 min-w-0">
96
- <p class="text-sm font-medium truncate">{{ ev.title }}</p>
108
+ <p class="text-sm flex items-center gap-1.5">
109
+ <span
110
+ v-if="!ev.read"
111
+ class="inline-block size-1.5 rounded-full bg-primary shrink-0"
112
+ aria-label="unread"
113
+ />
114
+ <span :class="ev.read ? 'font-normal text-muted' : 'font-medium'" class="truncate">
115
+ {{ ev.title }}
116
+ </span>
117
+ </p>
97
118
  <p v-if="ev.description" class="text-xs text-muted truncate">
98
119
  {{ ev.description }}
99
120
  </p>
@@ -63,6 +63,16 @@ function applyArchetype(arch: Archetype) {
63
63
  mode.value = 'description'
64
64
  }
65
65
 
66
+ // PR94b v3.48.0 — auto-apply archetype from query string (deep link
67
+ // from the /personas/archetypes catalog).
68
+ const route = useRoute()
69
+ watch(archetypes, (list) => {
70
+ const slug = String(route.query.archetype ?? '')
71
+ if (!slug || list.length === 0) return
72
+ const match = list.find((a) => a.id === slug)
73
+ if (match) applyArchetype(match)
74
+ }, { immediate: true })
75
+
66
76
  // ─── Step 2 state ────────────────────────────────────────────────────────
67
77
  const ingestJobs = ref<Array<{
68
78
  source: string
@@ -13,6 +13,7 @@ export interface ActivityEvent {
13
13
  title: string
14
14
  description?: string
15
15
  to?: string
16
+ read?: boolean
16
17
  }
17
18
 
18
19
  const STORAGE_KEY = 'arkaos_activity_feed'
@@ -21,7 +22,10 @@ const MAX_EVENTS = 50
21
22
  const _useActivityFeed = () => {
22
23
  const events = useState<ActivityEvent[]>('activityFeed', () => [])
23
24
  const loaded = useState<boolean>('activityFeedLoaded', () => false)
24
- const unreadCount = computed(() => events.value.length)
25
+ // PR94a v3.47.0 unread count is now derived from `read: false`.
26
+ const unreadCount = computed(
27
+ () => events.value.filter((e) => !e.read).length,
28
+ )
25
29
 
26
30
  function _persist() {
27
31
  if (typeof window === 'undefined') return
@@ -48,14 +52,39 @@ const _useActivityFeed = () => {
48
52
  loaded.value = true
49
53
  }
50
54
 
51
- function push(entry: Omit<ActivityEvent, 'id' | 'ts'>) {
55
+ function push(entry: Omit<ActivityEvent, 'id' | 'ts' | 'read'>) {
52
56
  load()
53
57
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
54
58
  const ts = new Date().toISOString()
55
- events.value = [{ id, ts, ...entry }, ...events.value].slice(0, MAX_EVENTS)
59
+ // PR94a every new event starts unread.
60
+ events.value = [{ id, ts, read: false, ...entry }, ...events.value].slice(0, MAX_EVENTS)
56
61
  _persist()
57
62
  }
58
63
 
64
+ function markRead(id: string) {
65
+ let changed = false
66
+ events.value = events.value.map((e) => {
67
+ if (e.id === id && !e.read) {
68
+ changed = true
69
+ return { ...e, read: true }
70
+ }
71
+ return e
72
+ })
73
+ if (changed) _persist()
74
+ }
75
+
76
+ function markAllRead() {
77
+ let changed = false
78
+ events.value = events.value.map((e) => {
79
+ if (!e.read) {
80
+ changed = true
81
+ return { ...e, read: true }
82
+ }
83
+ return e
84
+ })
85
+ if (changed) _persist()
86
+ }
87
+
59
88
  function clear() {
60
89
  events.value = []
61
90
  _persist()
@@ -66,7 +95,7 @@ const _useActivityFeed = () => {
66
95
  _persist()
67
96
  }
68
97
 
69
- return { events, unreadCount, load, push, clear, remove }
98
+ return { events, unreadCount, load, push, clear, remove, markRead, markAllRead }
70
99
  }
71
100
 
72
101
  export const useActivityFeed = createSharedComposable(_useActivityFeed)
@@ -0,0 +1,106 @@
1
+ <script setup lang="ts">
2
+ // PR94b v3.48.0 — Browseable catalog of persona archetypes.
3
+ //
4
+ // Reads /api/personas/archetypes (PR93b) and renders each as a card.
5
+ // "Create from this" deep-links to /personas/new?archetype=<id> where
6
+ // the wizard auto-selects description mode and pre-fills.
7
+
8
+ interface Archetype {
9
+ id: string
10
+ name: string
11
+ title: string
12
+ tagline: string
13
+ mbti: string
14
+ disc: { primary: string, secondary: string }
15
+ enneagram: { type: number, wing: number }
16
+ description: string
17
+ }
18
+
19
+ const { fetchApi } = useApi()
20
+ const { data, status, error, refresh } = await fetchApi<{
21
+ archetypes: Archetype[]
22
+ total: number
23
+ }>('/api/personas/archetypes')
24
+
25
+ const archetypes = computed<Archetype[]>(() => data.value?.archetypes ?? [])
26
+
27
+ function discColor(letter: string): 'error' | 'warning' | 'success' | 'primary' | 'neutral' {
28
+ const m: Record<string, 'error' | 'warning' | 'success' | 'primary' | 'neutral'> = {
29
+ D: 'error', I: 'warning', S: 'success', C: 'primary',
30
+ }
31
+ return m[letter] ?? 'neutral'
32
+ }
33
+ </script>
34
+
35
+ <template>
36
+ <UDashboardPanel id="archetypes">
37
+ <template #header>
38
+ <UDashboardNavbar title="Persona archetypes">
39
+ <template #leading>
40
+ <UButton icon="i-lucide-arrow-left" variant="ghost" size="sm" to="/personas" aria-label="Back" />
41
+ </template>
42
+ <template #trailing>
43
+ <UBadge v-if="data?.total" :label="String(data.total)" variant="subtle" />
44
+ </template>
45
+ </UDashboardNavbar>
46
+ </template>
47
+
48
+ <template #body>
49
+ <DashboardState
50
+ :status="status"
51
+ :error="error"
52
+ :empty="!archetypes.length"
53
+ empty-title="No archetypes available"
54
+ empty-icon="i-lucide-sparkles"
55
+ loading-label="Loading archetypes"
56
+ :on-retry="() => refresh()"
57
+ >
58
+ <p class="text-sm text-muted mb-6 max-w-2xl">
59
+ Curated starter profiles. Each one ships a description, behavioural DNA
60
+ defaults, and a recommended communication style. Use them as a base
61
+ when you don't have indexed content yet — the wizard pre-fills the
62
+ description and you tweak from there.
63
+ </p>
64
+
65
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
66
+ <div
67
+ v-for="arch in archetypes"
68
+ :key="arch.id"
69
+ class="rounded-xl border border-default p-5 flex flex-col gap-3 hover:border-primary/40 transition-colors"
70
+ >
71
+ <div>
72
+ <h3 class="text-lg font-bold">{{ arch.name }}</h3>
73
+ <p class="text-xs text-muted">{{ arch.title }}</p>
74
+ </div>
75
+ <p class="text-sm italic text-muted">"{{ arch.tagline }}"</p>
76
+ <div class="flex flex-wrap gap-1.5">
77
+ <UBadge :label="arch.mbti" variant="subtle" size="xs" />
78
+ <UBadge
79
+ :label="`DISC: ${arch.disc.primary}/${arch.disc.secondary}`"
80
+ :color="discColor(arch.disc.primary)"
81
+ variant="subtle"
82
+ size="xs"
83
+ />
84
+ <UBadge
85
+ :label="`E${arch.enneagram.type}w${arch.enneagram.wing}`"
86
+ variant="outline"
87
+ size="xs"
88
+ />
89
+ </div>
90
+ <p class="text-sm text-muted line-clamp-3">{{ arch.description }}</p>
91
+ <div class="pt-2 mt-auto">
92
+ <UButton
93
+ label="Create from this"
94
+ icon="i-lucide-sparkles"
95
+ color="primary"
96
+ size="sm"
97
+ block
98
+ :to="`/personas/new?archetype=${arch.id}`"
99
+ />
100
+ </div>
101
+ </div>
102
+ </div>
103
+ </DashboardState>
104
+ </template>
105
+ </UDashboardPanel>
106
+ </template>
@@ -423,6 +423,13 @@ async function undoTrashIds(ids: string[]) {
423
423
  />
424
424
  </template>
425
425
  <template #right>
426
+ <UButton
427
+ label="Archetypes"
428
+ icon="i-lucide-sparkles"
429
+ variant="ghost"
430
+ size="sm"
431
+ to="/personas/archetypes"
432
+ />
426
433
  <UButton
427
434
  label="Export ZIP"
428
435
  icon="i-lucide-archive"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkaos",
3
- "version": "3.46.0",
3
+ "version": "3.48.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.46.0"
3
+ version = "3.48.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"}