@agentprojectcontext/apx 1.70.0 → 1.71.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.
@@ -18,7 +18,7 @@
18
18
  <link rel="apple-touch-icon" href="/favicon/dark/apple-touch-icon.png" media="(prefers-color-scheme: dark)" />
19
19
  <link rel="manifest" href="/favicon/white/site.webmanifest" media="(prefers-color-scheme: light)" />
20
20
  <link rel="manifest" href="/favicon/dark/site.webmanifest" media="(prefers-color-scheme: dark)" />
21
- <script type="module" crossorigin src="/assets/index-YFsZFhM6.js"></script>
21
+ <script type="module" crossorigin src="/assets/index-CX15mZXM.js"></script>
22
22
  <link rel="stylesheet" crossorigin href="/assets/index-CDz9OwCP.css">
23
23
  </head>
24
24
  <body class="bg-background text-foreground antialiased">
@@ -1,7 +1,7 @@
1
1
  // Left-rail tab nav used inside Settings + per-project screens. Mirrors
2
2
  // the panda.project sectioned-nav pattern: optional section title above
3
3
  // each group, icon + label rows, active state in the section's tone.
4
- import { useState, useEffect, useCallback, Fragment, type ElementType } from "react";
4
+ import { useState, useEffect, useCallback, Fragment, type ElementType, type ReactNode } from "react";
5
5
  import { PanelLeft } from "lucide-react";
6
6
  import { cn } from "../../lib/cn";
7
7
  import { Tip } from "../ui/tip";
@@ -12,6 +12,9 @@ export interface TabItem {
12
12
  label: string;
13
13
  icon: ElementType;
14
14
  badge?: string | number;
15
+ // Small decoration (e.g. an Obsidian mark on "Memories" when the vault is
16
+ // wired) — trailing when expanded, a corner overlay when collapsed.
17
+ mark?: ReactNode;
15
18
  }
16
19
 
17
20
  export interface TabSection {
@@ -76,7 +79,7 @@ export function TabNav({ sections, active, onChange, collapsed = false }: TabNav
76
79
  </p>
77
80
  )}
78
81
  <div className="space-y-0.5">
79
- {section.items.map(({ key, label, icon: Icon, badge }) => {
82
+ {section.items.map(({ key, label, icon: Icon, badge, mark }) => {
80
83
  const isActive = active === key;
81
84
  const btn = (
82
85
  <button
@@ -84,7 +87,7 @@ export function TabNav({ sections, active, onChange, collapsed = false }: TabNav
84
87
  onClick={() => onChange(key)}
85
88
  data-testid={`tabnav-${key || "index"}`}
86
89
  className={cn(
87
- "flex cursor-pointer items-center rounded-lg transition-colors",
90
+ "relative flex cursor-pointer items-center rounded-lg transition-colors",
88
91
  collapsed ? "size-9 justify-center" : "w-full gap-2 px-2.5 py-1.5",
89
92
  isActive
90
93
  ? "bg-accent text-accent-fg"
@@ -92,9 +95,13 @@ export function TabNav({ sections, active, onChange, collapsed = false }: TabNav
92
95
  )}
93
96
  >
94
97
  <Icon className="size-4 shrink-0" />
98
+ {collapsed && mark && (
99
+ <span className="absolute -bottom-0.5 -right-0.5 flex items-center justify-center rounded-full bg-card">{mark}</span>
100
+ )}
95
101
  {!collapsed && (
96
102
  <>
97
103
  <span className="flex-1 truncate text-left text-xs">{label}</span>
104
+ {mark && <span className="flex shrink-0 items-center">{mark}</span>}
98
105
  {badge !== undefined && (
99
106
  <span className="rounded-full bg-muted px-1.5 text-[9px] text-muted-fg">{badge}</span>
100
107
  )}
@@ -1,4 +1,5 @@
1
1
  import { useMemo } from "react";
2
+ import useSWR from "swr";
2
3
  import { useParams, Routes, Route, Navigate, useLocation, useNavigate } from "react-router-dom";
3
4
  import {
4
5
  Bot, Heart, Zap, Puzzle, Settings,
@@ -8,6 +9,8 @@ import {
8
9
  } from "lucide-react";
9
10
  import { useNavCollapse, type TabSection } from "../components/common/TabNav";
10
11
  import { TabLayout } from "../components/common/TabLayout";
12
+ import { Integrations } from "../lib/api";
13
+ import { ObsidianLogo } from "../components/integrations/BrandLogos";
11
14
  import { RobyEmpty } from "../components/Roby";
12
15
  import { Button } from "../components/ui/button";
13
16
  import { useProject } from "../hooks/useProjects";
@@ -50,7 +53,14 @@ export function ProjectScreen() {
50
53
  const { collapsed, toggle } = useNavCollapse(STORAGE.sidebarCollapsed + ".project");
51
54
 
52
55
  const isBase = String(pid) === "0";
56
+ // Obsidian-backed memory: when the vault integration is active, mark the
57
+ // Memories nav item so it's clear memory is mirrored through the vault.
58
+ const { data: catalog } = useSWR(`integrations-catalog-${pid}`, () => Integrations.catalog(pid), { shouldRetryOnError: false });
59
+ const obsidianEntry = catalog?.find((e) => e.slug === "obsidian");
60
+ const obsidianActive = obsidianEntry?.status?.status === "active" && !!obsidianEntry?.status?.is_enabled;
61
+
53
62
  const sections: TabSection[] = useMemo(() => {
63
+ const memoriesMark = obsidianActive ? <ObsidianLogo className="size-3 text-purple-400" /> : undefined;
54
64
  // One shared taxonomy for both Base and projects, in the same order, so the
55
65
  // two menus mirror each other. Base additionally gets a "General" admin
56
66
  // section (workspaces / engines / agent defaults) and drops "Content"
@@ -76,7 +86,7 @@ export function ProjectScreen() {
76
86
  { key: "", label: t("project.nav.overview"), icon: LayoutDashboard },
77
87
  ...(isCompany ? [{ key: "structure", label: t("project.nav.structure"), icon: Building2 }] : []),
78
88
  { key: "agents", label: t("project.nav.agents"), icon: Bot },
79
- { key: "memories", label: t("project.nav.memories"), icon: Brain },
89
+ { key: "memories", label: t("project.nav.memories"), icon: Brain, mark: memoriesMark },
80
90
  { key: "skills", label: t("skills_page.title"), icon: Sparkles },
81
91
  { key: "artifacts", label: t("project.nav.artifacts"), icon: FileCode2 },
82
92
  ],
@@ -120,7 +130,7 @@ export function ProjectScreen() {
120
130
  ];
121
131
 
122
132
  return out.filter(Boolean) as TabSection[];
123
- }, [isBase, project?.kind]);
133
+ }, [isBase, project?.kind, obsidianActive]);
124
134
 
125
135
  // First path segment after /p/:pid — so deep routes like agents/:slug still
126
136
  // highlight the "agents" nav item.