arkaos 3.18.0 → 3.20.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 +1 -1
- package/core/personas/__pycache__/schema.cpython-313.pyc +0 -0
- package/dashboard/app/pages/agents/index.vue +54 -1
- package/dashboard/app/pages/personas/index.vue +66 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/__pycache__/dashboard-api.cpython-313.pyc +0 -0
- package/scripts/dashboard-api.py +60 -0
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.20.0
|
|
Binary file
|
|
@@ -91,6 +91,33 @@ const tierOptions = [
|
|
|
91
91
|
{ label: 'Tier 3 — Support', value: '3' }
|
|
92
92
|
]
|
|
93
93
|
|
|
94
|
+
// 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')
|
|
97
|
+
|
|
98
|
+
const discOptions = [
|
|
99
|
+
{ label: 'All DISC', value: 'all' },
|
|
100
|
+
{ label: 'D — Dominance', value: 'D' },
|
|
101
|
+
{ label: 'I — Influence', value: 'I' },
|
|
102
|
+
{ label: 'S — Steadiness', value: 'S' },
|
|
103
|
+
{ label: 'C — Conscientiousness', value: 'C' },
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
const mbtiGroupOptions = [
|
|
107
|
+
{ label: 'All MBTI groups', value: 'all' },
|
|
108
|
+
{ label: 'Analysts (NT)', value: 'analysts' },
|
|
109
|
+
{ label: 'Diplomats (NF)', value: 'diplomats' },
|
|
110
|
+
{ label: 'Sentinels (S__J)', value: 'sentinels' },
|
|
111
|
+
{ label: 'Explorers (S__P)', value: 'explorers' },
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
const MBTI_GROUPS: Record<string, string> = {
|
|
115
|
+
INTJ: 'analysts', INTP: 'analysts', ENTJ: 'analysts', ENTP: 'analysts',
|
|
116
|
+
INFJ: 'diplomats', INFP: 'diplomats', ENFJ: 'diplomats', ENFP: 'diplomats',
|
|
117
|
+
ISTJ: 'sentinels', ISFJ: 'sentinels', ESTJ: 'sentinels', ESFJ: 'sentinels',
|
|
118
|
+
ISTP: 'explorers', ISFP: 'explorers', ESTP: 'explorers', ESFP: 'explorers',
|
|
119
|
+
}
|
|
120
|
+
|
|
94
121
|
const filteredAgents = computed(() => {
|
|
95
122
|
let result = agents.value
|
|
96
123
|
const query = search.value.toLowerCase()
|
|
@@ -111,6 +138,16 @@ const filteredAgents = computed(() => {
|
|
|
111
138
|
result = result.filter(agent => String(agent.tier) === tierFilter.value)
|
|
112
139
|
}
|
|
113
140
|
|
|
141
|
+
if (discFilter.value !== 'all') {
|
|
142
|
+
result = result.filter(agent => agent.disc?.primary === discFilter.value)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (mbtiGroupFilter.value !== 'all') {
|
|
146
|
+
result = result.filter(
|
|
147
|
+
agent => MBTI_GROUPS[(agent.mbti ?? '').toUpperCase()] === mbtiGroupFilter.value,
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
114
151
|
if (favoritesOnly.value) {
|
|
115
152
|
result = result.filter(agent => favs.isAgentFavorite(agent.id))
|
|
116
153
|
}
|
|
@@ -127,7 +164,7 @@ const paginatedAgents = computed(() => {
|
|
|
127
164
|
|
|
128
165
|
const totalPages = computed(() => Math.max(1, Math.ceil(totalFiltered.value / pageSize)))
|
|
129
166
|
|
|
130
|
-
watch([search, departmentFilter, tierFilter], () => {
|
|
167
|
+
watch([search, departmentFilter, tierFilter, discFilter, mbtiGroupFilter], () => {
|
|
131
168
|
page.value = 1
|
|
132
169
|
})
|
|
133
170
|
|
|
@@ -381,6 +418,22 @@ async function undoTrashIds(ids: string[]) {
|
|
|
381
418
|
aria-label="Filter by tier"
|
|
382
419
|
/>
|
|
383
420
|
|
|
421
|
+
<USelect
|
|
422
|
+
v-model="discFilter"
|
|
423
|
+
:items="discOptions"
|
|
424
|
+
placeholder="DISC"
|
|
425
|
+
class="min-w-36"
|
|
426
|
+
aria-label="Filter by DISC primary"
|
|
427
|
+
/>
|
|
428
|
+
|
|
429
|
+
<USelect
|
|
430
|
+
v-model="mbtiGroupFilter"
|
|
431
|
+
:items="mbtiGroupOptions"
|
|
432
|
+
placeholder="MBTI group"
|
|
433
|
+
class="min-w-44"
|
|
434
|
+
aria-label="Filter by MBTI group"
|
|
435
|
+
/>
|
|
436
|
+
|
|
384
437
|
<UButton
|
|
385
438
|
:label="favoritesOnly ? 'All' : 'Favorites'"
|
|
386
439
|
:icon="favoritesOnly ? 'i-lucide-star' : 'i-lucide-star'"
|
|
@@ -142,6 +142,56 @@ const favs = useFavorites()
|
|
|
142
142
|
await favs.load()
|
|
143
143
|
const favoritesOnly = ref(false)
|
|
144
144
|
|
|
145
|
+
// PR87b v3.20.0 — import .md persona files.
|
|
146
|
+
const importInput = ref<HTMLInputElement | null>(null)
|
|
147
|
+
const importing = ref(false)
|
|
148
|
+
|
|
149
|
+
function triggerImport() {
|
|
150
|
+
importInput.value?.click()
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function onImportFiles(event: Event) {
|
|
154
|
+
const target = event.target as HTMLInputElement
|
|
155
|
+
const files = Array.from(target.files ?? [])
|
|
156
|
+
target.value = ''
|
|
157
|
+
if (files.length === 0) return
|
|
158
|
+
importing.value = true
|
|
159
|
+
try {
|
|
160
|
+
const payload = await Promise.all(
|
|
161
|
+
files.map(async (f) => ({
|
|
162
|
+
name: f.name,
|
|
163
|
+
content: await f.text(),
|
|
164
|
+
})),
|
|
165
|
+
)
|
|
166
|
+
const res = await $fetch<{
|
|
167
|
+
imported: number
|
|
168
|
+
failed: number
|
|
169
|
+
results: Array<{ filename: string, status: string, id?: string, error?: string }>
|
|
170
|
+
error?: string
|
|
171
|
+
}>(`${apiBase}/api/personas/import`, { method: 'POST', body: { files: payload } })
|
|
172
|
+
if (res.error) throw new Error(res.error)
|
|
173
|
+
toast.add({
|
|
174
|
+
title: res.imported > 0
|
|
175
|
+
? `Imported ${res.imported} persona${res.imported === 1 ? '' : 's'}`
|
|
176
|
+
: 'Nothing imported',
|
|
177
|
+
description: res.failed > 0 ? `${res.failed} failed` : undefined,
|
|
178
|
+
color: res.imported > 0 && res.failed === 0
|
|
179
|
+
? 'success'
|
|
180
|
+
: res.imported > 0 ? 'warning' : 'error',
|
|
181
|
+
icon: 'i-lucide-file-down',
|
|
182
|
+
})
|
|
183
|
+
await refreshAll()
|
|
184
|
+
} catch (err) {
|
|
185
|
+
toast.add({
|
|
186
|
+
title: 'Import failed',
|
|
187
|
+
description: err instanceof Error ? err.message : 'unknown error',
|
|
188
|
+
color: 'error',
|
|
189
|
+
})
|
|
190
|
+
} finally {
|
|
191
|
+
importing.value = false
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
145
195
|
// PR83b v3.4.0 — bulk selection + delete.
|
|
146
196
|
const toast = useToast()
|
|
147
197
|
const confirmDialog = useConfirmDialog()
|
|
@@ -262,6 +312,22 @@ async function undoTrashIds(ids: string[]) {
|
|
|
262
312
|
/>
|
|
263
313
|
</template>
|
|
264
314
|
<template #right>
|
|
315
|
+
<UButton
|
|
316
|
+
label="Import .md"
|
|
317
|
+
icon="i-lucide-file-up"
|
|
318
|
+
variant="soft"
|
|
319
|
+
size="sm"
|
|
320
|
+
:loading="importing"
|
|
321
|
+
@click="triggerImport"
|
|
322
|
+
/>
|
|
323
|
+
<input
|
|
324
|
+
ref="importInput"
|
|
325
|
+
type="file"
|
|
326
|
+
accept=".md,text/markdown"
|
|
327
|
+
multiple
|
|
328
|
+
class="hidden"
|
|
329
|
+
@change="onImportFiles"
|
|
330
|
+
/>
|
|
265
331
|
<UButton
|
|
266
332
|
label="New Persona"
|
|
267
333
|
icon="i-lucide-plus"
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
Binary file
|
package/scripts/dashboard-api.py
CHANGED
|
@@ -1494,6 +1494,66 @@ def global_search(q: str = "", limit: int = 20):
|
|
|
1494
1494
|
return {"results": results[: max(0, int(limit))]}
|
|
1495
1495
|
|
|
1496
1496
|
|
|
1497
|
+
# --- Persona import from Markdown (PR87b v3.20.0) ---
|
|
1498
|
+
|
|
1499
|
+
@app.post("/api/personas/import")
|
|
1500
|
+
def personas_import(body: dict):
|
|
1501
|
+
"""Import persona Markdown files (frontmatter + body) into the store.
|
|
1502
|
+
|
|
1503
|
+
Body: {"files": [{"name": "Alex.md", "content": "<full file body>"}]}
|
|
1504
|
+
Returns: {imported, failed, results: [{filename, status, id?, error?}]}
|
|
1505
|
+
|
|
1506
|
+
Each file MUST have YAML frontmatter with ``type: persona``. Files
|
|
1507
|
+
lacking the frontmatter are flagged as failed without partial
|
|
1508
|
+
side-effects.
|
|
1509
|
+
"""
|
|
1510
|
+
files = body.get("files") or []
|
|
1511
|
+
if not isinstance(files, list):
|
|
1512
|
+
return {"error": "files must be a list"}
|
|
1513
|
+
mgr = _get_persona_manager()
|
|
1514
|
+
if not mgr:
|
|
1515
|
+
return {"error": "Persona manager unavailable"}
|
|
1516
|
+
|
|
1517
|
+
from pathlib import Path as _Path
|
|
1518
|
+
|
|
1519
|
+
from core.personas.obsidian_store import ObsidianPersonaStore
|
|
1520
|
+
|
|
1521
|
+
imported = 0
|
|
1522
|
+
failed = 0
|
|
1523
|
+
results: list[dict] = []
|
|
1524
|
+
for entry in files:
|
|
1525
|
+
if not isinstance(entry, dict):
|
|
1526
|
+
failed += 1
|
|
1527
|
+
results.append({"filename": "(invalid)", "status": "failed", "error": "not an object"})
|
|
1528
|
+
continue
|
|
1529
|
+
filename = str(entry.get("name") or "")
|
|
1530
|
+
content = str(entry.get("content") or "")
|
|
1531
|
+
if not content.strip():
|
|
1532
|
+
failed += 1
|
|
1533
|
+
results.append({"filename": filename, "status": "failed", "error": "empty content"})
|
|
1534
|
+
continue
|
|
1535
|
+
fm = ObsidianPersonaStore._parse_frontmatter(content)
|
|
1536
|
+
if not fm or str(fm.get("type", "")).lower() != "persona":
|
|
1537
|
+
failed += 1
|
|
1538
|
+
results.append({
|
|
1539
|
+
"filename": filename, "status": "failed",
|
|
1540
|
+
"error": "missing or invalid frontmatter (type: persona required)",
|
|
1541
|
+
})
|
|
1542
|
+
continue
|
|
1543
|
+
try:
|
|
1544
|
+
persona = ObsidianPersonaStore._frontmatter_to_persona(
|
|
1545
|
+
fm, _Path(filename or "imported.md"),
|
|
1546
|
+
)
|
|
1547
|
+
mgr.create(persona)
|
|
1548
|
+
imported += 1
|
|
1549
|
+
results.append({"filename": filename, "status": "ok", "id": persona.id})
|
|
1550
|
+
except Exception as exc: # noqa: BLE001
|
|
1551
|
+
failed += 1
|
|
1552
|
+
results.append({"filename": filename, "status": "failed", "error": str(exc)})
|
|
1553
|
+
|
|
1554
|
+
return {"imported": imported, "failed": failed, "results": results}
|
|
1555
|
+
|
|
1556
|
+
|
|
1497
1557
|
# --- Trash / Undo (PR85b v3.12.0) ---
|
|
1498
1558
|
|
|
1499
1559
|
@app.get("/api/trash")
|