import * as React from 'react'; import { LayoutTemplate, Minus, Pencil, Plus, SearchX } from 'lucide-react'; import { Link } from 'react-router-dom'; import { cn } from '@/lib/utils'; import { Alert, Button, SearchInput, Switch } from '@/components/ds'; /** * Board skills, under the agent that stands beside them. * * The second half of one Skills section — the same heading, a tab away from the * Owliver catalog — so nobody has to decide between two top-level destinations * ever again. * * **Two controls, because there are two different questions.** This card used to * offer only the workspace switch, and said so at length: a Board skill was not * carried by an agent, because `SkillSurface` read the page and the account's * `disabledSkills` and never looked at `agent.skills`. That was true, and it is * not any more — `useSkillSections` now asks `agentPermitsSkill`, so an id * written into `agent.skills` is honoured on the page. * * So both questions are asked here, and neither is dressed up as the other: * * - **Active** is the workspace switch. Off means off for everyone, on every * page, for every agent. It is the account's `disabledSkills`. * - **Add to agent** is ownership. It writes this skill's id into * `agent.skills`, through the same handler the Owliver catalog uses. * * Ownership is opt-in and that is what makes the two safe together: a skill no * agent claims still draws wherever its `pages:` say, exactly as before. The * first agent to claim it is what narrows it — which is why attaching is worth * saying out loud on the card rather than leaving as a silent side effect. */ /** One Board skill: what it draws, where, and whether it is switched on. */ function BoardCard({ entry, enabled, onToggle, onSurfaces, busy, attached = false, onAttach = null }) { const switchId = `board-${entry.id}`; return (
  • {/* Soft Background Highlight on Hover */}
    Board Skill
    {enabled ? 'Active' : 'Disabled'} onToggle(entry.id, next)} aria-label={`${entry.name} — ${enabled ? 'on' : 'off'} for this workspace`} />

    {entry.name}

    {entry.description && (

    {entry.description}

    )} {/* What it actually draws. */} {entry.sections.length > 0 && (
      {entry.sections.map((section, i) => (
    • {section.title} · {section.typeLabel} · {section.pageLabel} / {section.placementLabel}
    • ))}
    )}
    {/* Ownership, separate from the workspace switch above it. The button writes `agent.skills` through the same handler the Owliver catalog uses — there is no second assignment path and nothing new stored. */} {onAttach && (
    {attached ? 'Owned by this agent' : 'Not owned by any agent on this page'}
    )}
    {entry.surfaces.some((s) => onSurfaces.has(s.id)) ? 'Active on this agent\'s pages' : 'Draws across workspace'}
  • ); } export function BoardSkillList({ entries, agentPages = [], disabledIds, onToggle, busy = false, query, onQueryChange, total, attachedIds = null, onAttach = null, }: any) { const searchId = React.useId(); const onSurfaces = React.useMemo(() => new Set(agentPages), [agentPages]); /* The ones that meet this agent first */ const ordered = React.useMemo(() => { const here = []; const elsewhere = []; for (const e of entries) { (e.surfaces.some((s) => onSurfaces.has(s.id)) ? here : elsewhere).push(e); } return [...here, ...elsewhere]; }, [entries, onSurfaces]); return (
    Active is workspace-wide: off means off on every page, for every agent. Add to agent is ownership — once any agent owns a board skill, it draws only where an owning agent is answering. A skill no agent owns keeps drawing wherever its pages say, as before. {total > 0 && (
    )} {total > 0 && (

    {ordered.length} of {total} board skill{total === 1 ? '' : 's'}

    )} {ordered.length > 0 ? ( ) : (
    {total > 0 ? ( <>
    )}
    ); } export default BoardSkillList;