arkaos 3.28.0 → 3.29.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.28.0
1
+ 3.29.0
@@ -50,6 +50,45 @@ watch(profile, (p) => {
50
50
 
51
51
  const savingProfile = ref(false)
52
52
 
53
+ // PR89c v3.29.0 — vault connection test.
54
+ interface VaultStatus {
55
+ configured: boolean
56
+ vault_path: string
57
+ exists: boolean
58
+ personas: { dir: string, count: number }
59
+ agents: { dir: string, count: number }
60
+ }
61
+ const vaultStatus = ref<VaultStatus | null>(null)
62
+ const testingVault = ref(false)
63
+
64
+ async function testVault() {
65
+ testingVault.value = true
66
+ try {
67
+ // Save first so the backend reads the current value
68
+ if (profileDraft.value.vaultPath !== profile.value?.vaultPath) {
69
+ await $fetch(`${apiBase}/api/profile`, {
70
+ method: 'POST',
71
+ body: { vaultPath: profileDraft.value.vaultPath },
72
+ })
73
+ }
74
+ vaultStatus.value = await $fetch<VaultStatus>(`${apiBase}/api/settings/vault`)
75
+ toast.add({
76
+ title: vaultStatus.value.exists ? 'Vault reachable' : 'Vault not found',
77
+ description: vaultStatus.value.vault_path || 'Set a path first',
78
+ color: vaultStatus.value.exists ? 'success' : 'warning',
79
+ icon: vaultStatus.value.exists ? 'i-lucide-check-circle' : 'i-lucide-alert-circle',
80
+ })
81
+ } catch (err) {
82
+ toast.add({
83
+ title: 'Test failed',
84
+ description: err instanceof Error ? err.message : 'unknown error',
85
+ color: 'error',
86
+ })
87
+ } finally {
88
+ testingVault.value = false
89
+ }
90
+ }
91
+
53
92
  async function saveProfile() {
54
93
  savingProfile.value = true
55
94
  try {
@@ -326,8 +365,18 @@ const activeSection = ref<SectionId>('profile')
326
365
 
327
366
  <UFormField
328
367
  label="Vault path"
329
- help="Where your Obsidian vault lives. Used by the KB-first hook."
368
+ help="Where your Obsidian vault lives. Used by the KB-first hook + Persona/Agent exporters."
330
369
  >
370
+ <template #hint>
371
+ <UButton
372
+ label="Test connection"
373
+ icon="i-lucide-plug-zap"
374
+ size="xs"
375
+ variant="soft"
376
+ :loading="testingVault"
377
+ @click="testVault"
378
+ />
379
+ </template>
331
380
  <UInput
332
381
  v-model="profileDraft.vaultPath"
333
382
  placeholder="/Users/you/Documents/Vault"
@@ -335,6 +384,50 @@ const activeSection = ref<SectionId>('profile')
335
384
  />
336
385
  </UFormField>
337
386
 
387
+ <!-- PR89c v3.29.0 — vault connection test result -->
388
+ <div
389
+ v-if="vaultStatus"
390
+ class="rounded-lg border p-3 text-xs space-y-1"
391
+ :class="
392
+ vaultStatus.exists
393
+ ? 'border-emerald-500/40 bg-emerald-500/5'
394
+ : 'border-yellow-500/40 bg-yellow-500/5'
395
+ "
396
+ >
397
+ <div class="flex items-center gap-2 font-semibold">
398
+ <UIcon
399
+ :name="vaultStatus.exists ? 'i-lucide-check-circle' : 'i-lucide-alert-circle'"
400
+ :class="vaultStatus.exists ? 'text-emerald-500 size-4' : 'text-yellow-500 size-4'"
401
+ />
402
+ <span v-if="!vaultStatus.configured">Vault not configured</span>
403
+ <span v-else-if="!vaultStatus.exists">Path does not exist</span>
404
+ <span v-else>Vault reachable</span>
405
+ </div>
406
+ <p v-if="vaultStatus.exists" class="text-muted font-mono">
407
+ {{ vaultStatus.vault_path }}
408
+ </p>
409
+ <ul v-if="vaultStatus.exists" class="space-y-0.5 pt-1">
410
+ <li class="flex items-center gap-2">
411
+ <UIcon name="i-lucide-folder" class="size-3 text-muted" />
412
+ <span class="font-mono">Personas/</span>
413
+ <UBadge
414
+ :label="`${vaultStatus.personas.count} files`"
415
+ variant="subtle"
416
+ size="xs"
417
+ />
418
+ </li>
419
+ <li class="flex items-center gap-2">
420
+ <UIcon name="i-lucide-folder" class="size-3 text-muted" />
421
+ <span class="font-mono">Agents/</span>
422
+ <UBadge
423
+ :label="`${vaultStatus.agents.count} files`"
424
+ variant="subtle"
425
+ size="xs"
426
+ />
427
+ </li>
428
+ </ul>
429
+ </div>
430
+
338
431
  <div class="flex justify-end pt-2">
339
432
  <UButton
340
433
  label="Save profile"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkaos",
3
- "version": "3.28.0",
3
+ "version": "3.29.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.28.0"
3
+ version = "3.29.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"}
@@ -2500,6 +2500,44 @@ def settings_plugins():
2500
2500
 
2501
2501
  # --- Profile (PR63 v2.81.0) ---
2502
2502
 
2503
+ @app.get("/api/settings/vault")
2504
+ def settings_vault():
2505
+ """PR89c v3.29.0 — vault path connection test.
2506
+
2507
+ Reads ``profile.vaultPath`` and reports back whether the path
2508
+ exists, whether ``Personas/`` and ``Agents/`` subdirs are present,
2509
+ and how many ``*.md`` files each contains.
2510
+
2511
+ Returns ``{configured, vault_path, exists, personas: {dir, count},
2512
+ agents: {dir, count}}``.
2513
+ """
2514
+ from core.profile import ProfileManager
2515
+ profile = ProfileManager().read()
2516
+ configured = bool(profile.vaultPath)
2517
+ vault = Path(profile.vaultPath).expanduser() if configured else None
2518
+ exists = bool(vault and vault.exists() and vault.is_dir())
2519
+
2520
+ def _subdir_info(name: str) -> dict:
2521
+ if not exists:
2522
+ return {"dir": "", "count": 0}
2523
+ sub = vault / name
2524
+ if not sub.exists():
2525
+ return {"dir": str(sub), "count": 0}
2526
+ try:
2527
+ count = sum(1 for _ in sub.glob("*.md"))
2528
+ except OSError:
2529
+ count = 0
2530
+ return {"dir": str(sub), "count": count}
2531
+
2532
+ return {
2533
+ "configured": configured,
2534
+ "vault_path": str(vault) if vault else "",
2535
+ "exists": exists,
2536
+ "personas": _subdir_info("Personas"),
2537
+ "agents": _subdir_info("Agents"),
2538
+ }
2539
+
2540
+
2503
2541
  @app.get("/api/profile")
2504
2542
  def profile_get():
2505
2543
  """Return the operator profile from ~/.arkaos/profile.json.