import * as react from 'react'; import { ReactNode, SVGProps, ComponentType } from 'react'; import { l as AssociationEdge, m as AssociationsEntry, n as AssociationTargetType, k as AssociationWriteResult, E as EntityTypeToken, o as CaptureShownTo, a as CategoryDimension, d as PlatformComment } from './store-BDkADbPU.js'; import { GlyphComponent } from '@ai-matrx/design-system/icons'; interface UseAssociationsArgs { /** The entity whose relationships to read/manage (the cache endpoint). */ type: string; id: string | null; /** Disable the auto-load on mount. Defaults to false (auto-load). */ autoLoad?: boolean; } interface UseAssociationsReturn { /** Every edge touching this entity, both directions. */ edges: AssociationEdge[]; status: AssociationsEntry["status"]; error: string | null; fetchedAt: number | null; /** Attach this entity (as source) → a target. */ add: (args: { targetType: AssociationTargetType; targetId: string; orgId?: string; label?: string; /** Typed edge role (e.g. 'theme' for a folder/tag) — omit for a role-less edge. */ role?: string; }) => Promise; /** Detach this entity (as source) → a target. */ remove: (args: { targetType: string; targetId: string; role?: string; }) => Promise; /** Replace this entity's edges of one target type with exactly `targetIds`. */ setTargets: (args: { targetType: AssociationTargetType; targetIds: string[]; orgId?: string; role?: string; }) => Promise; /** Force a refetch of this entity's edges. */ reload: () => Promise; } declare function useAssociations(args: UseAssociationsArgs): UseAssociationsReturn; /** * Convenience alias — same hook, a name that reads naturally on relationship * surfaces ("the things this entity is related to"). Identical contract. */ declare const useEntityRelationships: typeof useAssociations; interface PrimaryEntityBase { id: string; /** Org to stamp on edges created here (org-scoped RLS / counts). */ orgId?: string | null; /** Human label for headings (e.g. the org/scope name). */ label?: string; } /** A container: its surfaces list what is attached INTO it (the default). */ interface PrimaryContainerEntity extends PrimaryEntityBase { /** Container token — must be an association TARGET type. */ type: AssociationTargetType; direction?: "incoming"; } /** * A thing FILED UNDER containers (e.g. a Source under a project): its * surfaces list its own outgoing edges and "+" files it under a container. */ interface PrimaryFiledEntity extends PrimaryEntityBase { /** Any registered entity type — it is the edge SOURCE. */ type: EntityTypeToken; direction: "outgoing"; } /** The primary entity a surface is anchored to. */ type PrimaryEntity = PrimaryContainerEntity | PrimaryFiledEntity; declare function PrimaryEntityProvider({ value, children, }: { value: PrimaryEntity; children: ReactNode; }): react.JSX.Element; /** Read the surrounding primary entity, or null when unprovided. */ declare function usePrimaryEntity(): PrimaryEntity | null; interface ContainerLink { /** The edge id (for keys / removal). */ edgeId: string; /** The attached resource's id (the edge source). */ resourceId: string; /** The attached resource's entity token (the edge source type). */ token: string; /** The edge role, or null for a plain (role-less) association. */ role: string | null; label: string | null; /** Per-edge props from `platform.associations.metadata` (e.g. representation). */ metadata: unknown; } interface UseContainerLinksBase { containerId: string | null; /** Org to stamp on new edges (for org-scoped RLS / counts). */ orgId?: string | null; } /** * `incoming` (default): the primary is a container (edge TARGET) — links are * what is attached into it. `outgoing`: the primary is filed under containers * (edge SOURCE) — links are the containers it is filed under, and `attach` * writes `primary → container` (the same role-less edge the landing door * writes), refusing tokens that are not container types. */ type UseContainerLinksArgs = (UseContainerLinksBase & { containerType: AssociationTargetType; direction?: "incoming"; }) | (UseContainerLinksBase & { containerType: EntityTypeToken; direction: "outgoing"; }); interface UseContainerLinksReturn { status: ReturnType["status"]; error: string | null; reload: () => Promise; /** Total attached resources across every token (all incoming edges). */ totalCount: number; /** Live count of attached resources of `token`. */ countFor: (token: EntityTypeToken) => number; /** Ids of resources of `token` already attached (for picker "attached" state). */ attachedIdsFor: (token: EntityTypeToken) => Set; /** Full link rows of `token` (for listing/removal). */ linksFor: (token: EntityTypeToken) => ContainerLink[]; /** Every token that has at least one link, in first-seen order. */ presentTokens: string[]; /** Attach a resource (source) to this container (target). */ attach: (token: EntityTypeToken, resourceId: string, label?: string, metadata?: unknown, options?: { replaceMetadata?: boolean; /** * Semantic edge role (`platform.associations.role`) — e.g. the * Masterwork dump surface stamps `distillation_source`. Omitted = the * canonical role-less edge. Detach with the SAME role to remove it. */ role?: string; }) => Promise; /** Detach a resource from this container. */ detach: (token: EntityTypeToken, resourceId: string, role?: string) => Promise; /** * Toggle the edge's agent-context pin while preserving every other metadata * field and the exact semantic role. */ setPinned: (token: EntityTypeToken, resourceId: string, pinned: boolean, role?: string) => Promise; } /** * Which way a container's links of `token` point, by the registry. * `from-container` only when `container → token` is registered and * `token → container` is not; otherwise the canonical incoming direction. */ declare function linkDirection(containerType: string, token: string): "into-container" | "from-container"; declare function useContainerLinks(args: UseContainerLinksArgs): UseContainerLinksReturn; /** * `useContainerLinks` args for a surface's primary entity — the ONE mapping * the faces (card, list) use, so a primary's direction is never dropped. */ declare function containerLinksArgs(container: PrimaryEntity | null): UseContainerLinksArgs; interface AssociationEntitySelectItem { id: string; title: string; } /** * The read/write seam of the association "name dropdown". This hook is the * default (plain associations container); surfaces with bespoke active/create * semantics implement it themselves — same pattern as AssociationList's * ContainerResourcesAdapter. */ interface AssociationEntitySelectAdapter { /** True while the association list is still hydrating. */ loading: boolean; /** Every entity of this token associated with the container. */ items: AssociationEntitySelectItem[]; activeId: string | null; setActive: (id: string) => void | Promise; /** * Create a new entity named `title`, associate it to the container, and * make it active. Resolves to the new id, or null on failure (the adapter * reports its own error detail; the component toasts generically). * Omit when creation isn't name-driven — pass `createSlot` on the component * instead (e.g. a conversation is created by PICKING AN AGENT, not naming). */ createAndAttach?: (title: string) => Promise; /** Rename the entity (its real title column). Resolves false on failure. */ rename: (id: string, title: string) => Promise; /** Optional: unlink an entity from the container (never deletes the row). */ detach?: (id: string) => Promise; } interface UseAssociationEntitySelectAdapterArgs { token: EntityTypeToken; /** The container the entities are associated with (always the edge TARGET). */ container: { type: AssociationTargetType; id: string | null; orgId?: string | null; }; /** Controlled active selection; omit to default to the first attached row. */ activeId?: string | null; onActiveChange?: (id: string) => void | Promise; /** NOT NULL columns the registry conventions can't know (create only). */ createColumns?: Record; } declare function useAssociationEntitySelectAdapter(args: UseAssociationEntitySelectAdapterArgs): AssociationEntitySelectAdapter; interface AssociationWindowProps { /** Controls mount — callers should also gate their JSX on this. */ open: boolean; onClose: () => void; /** Human-readable scope for the window id (debugging / tray labels). */ scopeId: string; title: string; /** Small leading icon rendered beside the title. */ icon?: ReactNode; /** * One-line context under the header ("Attached to Titanium Marketing"). * A node, not a string, so the container it names can carry its own door * (THE DOOR LAW) instead of being an unreachable label. */ subtitle?: ReactNode; children: ReactNode; } declare function AssociationWindow({ open, onClose, scopeId, title, icon, subtitle, children, }: AssociationWindowProps): react.JSX.Element | null; interface UniversalAssociationPickerProps { /** Tokens offered. Defaults to every listable token. */ tokens?: EntityTypeToken[]; /** Ids already attached, keyed `${token}:${id}` — rendered as attached. */ attachedKeys: Set; onAttach: (token: EntityTypeToken, resourceId: string, title: string) => Promise<{ ok: boolean; error?: string; }>; onDetach: (token: EntityTypeToken, resourceId: string) => Promise<{ ok: boolean; error?: string; }>; /** Org stamped onto rows created via the per-token "+ New" footer. */ orgId?: string | null; /** * What an empty search box shows. `"recents"` (default) shows favorites and * last-viewed records and falls back to browsing candidates when there are * none; `"candidates"` always browses the available records. */ emptyQueryMode?: "recents" | "candidates"; className?: string; } declare function attachedKey(token: string, id: string): string; declare function UniversalAssociationPicker(props: UniversalAssociationPickerProps): react.JSX.Element; interface AttachedItemsSheetProps { open: boolean; onOpenChange: (open: boolean) => void; token: EntityTypeToken; containerLabel?: string; /** * The container these items are attached to. When given, the "Attached to X" * line puts a door on X — this window can outlive the page it was opened * from, so its container reference must be reachable. */ container?: PrimaryEntity; links: ContainerLink[]; /** Opens the attach picker. Omitted when the token cannot list candidates. */ onAdd?: () => void; onDetach: (resourceId: string, role?: string | null) => Promise<{ ok: boolean; error?: string; }>; /** Toggle metadata.pinned on this exact role-qualified edge. */ onSetPinned?: (resourceId: string, pinned: boolean, role?: string | null) => Promise<{ ok: boolean; error?: string; }>; } declare function AttachedItemsSheet(props: AttachedItemsSheetProps): react.JSX.Element | null; interface AssociationCardProps { /** The secondary entity kind this card manages (e.g. "task", "file"). */ token: EntityTypeToken; /** Override the page's primary entity. Defaults to PrimaryEntityProvider. */ container?: PrimaryEntity; /** * "tiles" (default, everywhere): the tinted icon chip, role-colored top bar, * "N attached" line and square "+". Opt-in one-line looks for pages that do * not want the full card: "simplified" (square "+") and "compact" (the * outline PlusTapButton — the CRM record's look). */ look?: AssociationCardLook; className?: string; } type AssociationCardLook = "tiles" | "simplified" | "compact"; declare function AssociationCard({ token, container: containerProp, look, className, }: AssociationCardProps): react.JSX.Element | null; interface AssociationCardGridProps { /** Tokens to show. Defaults to every registry-listable token. */ tokens?: EntityTypeToken[]; /** Registry tokens this surface cannot honestly support yet. */ excludeTokens?: EntityTypeToken[]; /** * "tiles" (default, everywhere): each group has a colored dot, its title and * a one-line description; cards sit in a 1/2/3-column grid. Opt-in * "simplified" / "compact": an uppercase eyebrow over wrapping one-line * cards (see AssociationCard for the two "+" buttons). */ look?: AssociationCardLook; className?: string; } declare function AssociationCardGrid({ tokens, excludeTokens, look, className, }: AssociationCardGridProps): react.JSX.Element; /** One attached resource, as the list renders it. Tokens are CANONICAL. */ interface ContainerResourceRow { /** Stable row key (edge id or `${token}:${id}`). */ key: string; token: string; resourceId: string; label: string | null; /** Exact semantic edge role; null means the canonical role-less edge. */ role?: string | null; /** Pinned rows sort first inside their token group. */ pinned?: boolean; /** False for inherited rows (e.g. via a thread's anchor) — no detach. */ removable: boolean; /** Small annotation for non-removable rows ("via anchor"). */ originNote?: string | null; /** Resolvable records that contributed an inherited row. */ originRefs?: readonly { token: EntityTypeToken; id: string; label: string; }[]; } interface ContainerResourcesAdapter { status: "idle" | "loading" | "ready" | "error"; error: string | null; reload: () => void | Promise; rows: ContainerResourceRow[]; attach: (token: EntityTypeToken, resourceId: string, title?: string, /** * Extra edge metadata stamped at attach time (label-at-attach-time's * sibling contract). Adapters without metadata support may ignore it. */ opts?: { metadata?: Record | null; }) => Promise<{ ok: boolean; error?: string; }>; detach: (token: EntityTypeToken, resourceId: string, role?: string) => Promise<{ ok: boolean; error?: string; }>; /** * Optional pin capability (edge `metadata.pinned`) — pinned resources stay * inline in agent context at every tier. Rows show a pin toggle when set. */ setPinned?: (token: EntityTypeToken, resourceId: string, pinned: boolean, role?: string) => Promise<{ ok: boolean; error?: string; }>; } /** Default adapter — wraps `useContainerLinks` (org/scope/project pages). */ declare function useContainerLinksAdapter(container: PrimaryEntity | null, tokens?: readonly EntityTypeToken[]): ContainerResourcesAdapter; interface AssociationListProps { /** Container override; defaults to the surrounding PrimaryEntityProvider. */ container?: PrimaryEntity; /** Write/read override (war-room threads etc.). Default: useContainerLinks. */ adapter?: ContainerResourcesAdapter; /** Restrict display + attach to these tokens (e.g. one dynamic tab). */ tokens?: EntityTypeToken[]; /** `full` = role sections + universal search; `compact` = flat token groups. */ variant?: "full" | "compact"; /** Extra per-token actions (e.g. war-room Upload / New document). */ renderSectionActions?: (token: EntityTypeToken) => ReactNode; /** Open a resource. Default: registry `hrefFor` in a new tab. */ openEntity?: (token: string, id: string) => void; /** * Per-token row override (return null/undefined to keep the default row) — * for rows that need richer rendering than icon+title. The override owns the * whole row; use `ctx` for the resolved title and the busy/detach/open * wiring. */ renderRow?: (row: ContainerResourceRow, ctx: { title: string; busy: boolean; onDetach: () => void; onOpen: () => void; }) => ReactNode | null | undefined; /** * The list's own heading. Default "Resources". `null` when the host card already titles the list: * the count and the attach controls stay, right-aligned. */ title?: string | null; className?: string; } declare function AssociationList(props: AssociationListProps): react.JSX.Element; /** * react/icons.tsx — this package's glyph names, as aliases of the ONE glyph home, * `@ai-matrx/design-system/icons`. No path data lives here (policy C19: no icon library, and one drawing per * glyph); the alias only fixes this package's historical size and stroke. Exports are unchanged. */ type IconProps = SVGProps; declare const DefaultEntityIcon: GlyphComponent; interface CaptureAttachResult { ok: boolean; /** Human error text — the toolbar screams it. Omit when the host already did. */ error?: string; } /** * ONE write callback for every capture verb. Tokens are canonical * (`file` / `udt_document`); the host maps to its own write path (an * association edge, a thread thunk, …) and reports the outcome honestly — * a silent no-op attach is the bug class this contract kills. */ type CaptureAttach = (token: EntityTypeToken, resourceId: string, opts?: { label?: string; }) => Promise; interface AssociationCaptureToolbarProps { attach: CaptureAttach; /** Logical cloud-files folder new uploads land in (auto-created). */ uploadFolderPath: string; /** Publish uploads to the web. Default false — every upload writes it explicitly. */ uploadPublishedToWeb?: boolean; /** "Shown to" stamped on uploads. Default "only_me". */ uploadShownTo?: CaptureShownTo; /** * Where a created-but-unlinked upload is reported to live, e.g. * "your Files (War Room folder)". Keeps the loud-outcome copy honest. */ uploadLocationLabel: string; /** The retry verb named in loud-outcome copy. Default '"Add file"'. */ attachRetryLabel?: string; /** Copy for the existing-files picker dialog. */ filePicker?: { title?: string; description?: string; }; /** Which built-in actions render (each ALSO gated on its port handler). */ showActions?: { upload?: boolean; addFile?: boolean; newDocument?: boolean; }; /** Hide the button row (compact variants) — drag-and-drop stays live. */ showToolbar?: boolean; /** Extra host-specific buttons appended after the built-ins. */ extraActions?: ReactNode; /** * Authoritative organization for this container. Never inferred from global * selection. */ organizationId?: string | null; /** Open a freshly created document via the registry door. Default true. */ openCreatedDocument?: boolean; className?: string; /** The body the drop target wraps (the list of attached things). */ children?: ReactNode; } declare function AssociationCaptureToolbar({ attach, uploadFolderPath, uploadPublishedToWeb, uploadShownTo, uploadLocationLabel, attachRetryLabel, filePicker, showActions, showToolbar, extraActions, organizationId, openCreatedDocument, className, children, }: AssociationCaptureToolbarProps): react.JSX.Element; /** The dense toolbar button (exported so hosts' extraActions match). */ declare function CaptureToolbarAction({ icon: Icon, label, onClick, disabled, spinning, }: { icon: (props: IconProps) => ReactNode; label: string; onClick: () => void; disabled?: boolean; spinning?: boolean; }): react.JSX.Element; interface AssociationEntitySelectProps { token: EntityTypeToken; adapter: AssociationEntitySelectAdapter; className?: string; /** Label sizing/typography override (defaults to toolbar-dense text-xs). */ labelClassName?: string; align?: "start" | "end"; showIcon?: boolean; /** How the name enters inline edit. Default "click". */ renameActivation?: "click" | "doubleClick"; /** Shown while no entity is active yet. Defaults to the plural label. */ emptyLabel?: string; /** Icon color accent (e.g. "text-yellow-500" for notes). */ iconClassName?: string; /** * Replaces the default "+ New " name-input footer with a custom * creator (e.g. an agent picker that starts a new chat). Function form * receives `close` so the creator can dismiss the dropdown when done. */ createSlot?: React.ReactNode | ((close: () => void) => React.ReactNode); } declare function AssociationEntitySelect({ token, adapter, className, labelClassName, align, showIcon, renameActivation, emptyLabel, iconClassName, createSlot, }: AssociationEntitySelectProps): react.JSX.Element; interface CategorySelectProps { dimension: CategoryDimension; value: string | null; onChange: (id: string | null) => void; placeholder: string; allowNone?: boolean; disabled?: boolean; /** * Offer "Create «what you typed»". On by default — a closed category list is * a defect, so turning this off needs a reason a person would accept. */ allowCreate?: boolean; /** * Org for an inline-created category. Defaults to the identity port's * `ensureOrgId()`; with neither, create refuses loudly. */ orgId?: string | null; /** What one of these is called, for the create affordance ("stage", "folder"). */ noun?: string; } declare function CategorySelect({ dimension, value, onChange, placeholder, allowNone, disabled, allowCreate, orgId, noun, }: CategorySelectProps): react.JSX.Element; /** Structural stand-in for the host's `LucideIcon` on the `icon` prop. */ type TagPickerIcon = ComponentType<{ className?: string; }>; interface CategoryTagPickerProps { /** The tagged entity's registered association type (e.g. "fc_set", "party"). */ entityType: string; entityId: string; /** The `platform.categories` facet the picker offers. */ dimension: CategoryDimension; /** The typed edge role the assignment edges carry (e.g. "theme", "member"). */ edgeRole: string; /** * Org for the edge write and for inline-created categories. Defaults to the * identity port's `ensureOrgId()` (create only) — pass the owning entity's * org when it has one. */ orgId?: string | null; /** Trigger label while nothing is selected. */ addLabel?: string; /** Trigger icon. */ icon?: TagPickerIcon; /** Offer "Create " for unmatched search terms. Default true. */ allowCreate?: boolean; /** * Force the two-level face on or off. Omit to detect it from parentId rows, * which leaves every existing flat facet visually unchanged. */ hierarchical?: boolean; emptyText?: string; } /** * Multi-select combobox: badges for the entity's current tags in `dimension`, * a popover to toggle existing categories, optional inline create. Fully * self-contained — mount it once per entity and it reads/writes the edges. */ declare function CategoryTagPicker({ entityType, entityId, dimension, edgeRole, orgId, addLabel, icon: Icon, allowCreate, hierarchical, emptyText, }: CategoryTagPickerProps): react.JSX.Element; interface CommentThreadProps { /** Entity-type token of the commented-on entity. */ token: EntityTypeToken; /** The entity's row id. */ id: string; /** * Org override forwarded to `cmt_add`. Optional: the RPC reads the commented * record's OWN organization when this is omitted, and refuses a value that * disagrees with it (22023). It never falls back to the author's workspace. */ orgId?: string | null; /** Hide the slim "Comments · n" header row. Defaults to shown. */ showHeader?: boolean; /** * Told once per comment the person posts here (a new comment or a reply), * after the door saved it. The host decides what follows (e.g. the comment * rides along with the person's next chat message). Never called on a failure. */ onPosted?: (posted: PostedComment) => void; /** * The thread is about ONE PART of the record (a board-only tile): the * thread shows only that part's comments (and their replies), and a new * comment is stored with a `part_anchor` naming it. Omitted = the whole * record's thread, where each part comment carries its part's name. */ part?: { key: string; label: string; }; className?: string; } /** What `onPosted` is told: the saved row's id, the words, and the comment it answers. */ interface PostedComment { id: string; body: string; /** The comment this one replies to; null for a new top-level comment. */ parentId: string | null; } interface CommentComposerProps { /** Post the body; resolve `{ok:false}` to keep the text + show the error. */ onSubmit: (body: string) => Promise<{ ok: boolean; error?: string; }>; placeholder?: string; submitLabel?: string; /** Initial body (the edit flow seeds the current text). */ initialValue?: string; /** Rendered right of the submit button (the Cancel affordance). */ trailing?: ReactNode; autoFocus?: boolean; } /** * The one composer every comment write goes through (new comment, reply, * edit). Submit on the button or Cmd/Ctrl+Enter; the text survives a failed * submit alongside the inline error (input is never lost). */ declare function CommentComposer({ onSubmit, placeholder, submitLabel, initialValue, trailing, autoFocus, }: CommentComposerProps): react.JSX.Element; /** * Build the parent→children index. A reply whose parent is missing from the * list (soft-deleted parent, partial page) is promoted to top level rather * than dropped — every visible comment stays reachable. */ declare function buildCommentTree(comments: readonly PlatformComment[]): { roots: PlatformComment[]; childrenOf: Map; }; declare function CommentThread({ token, id, orgId, showHeader, onPosted, part, className, }: CommentThreadProps): react.JSX.Element; export { useEntityRelationships as $, DefaultEntityIcon as F, PrimaryEntityProvider as I, UniversalAssociationPicker as K, attachedKey as R, buildCommentTree as S, containerLinksArgs as V, linkDirection as W, useAssociationEntitySelectAdapter as X, useAssociations as Y, useContainerLinks as Z, useContainerLinksAdapter as _, usePrimaryEntity as a0, AssociationCaptureToolbar as i, AssociationCard as j, AssociationCardGrid as k, AssociationEntitySelect as m, AssociationList as p, AssociationWindow as q, AttachedItemsSheet as r, CaptureToolbarAction as u, CategorySelect as v, CategoryTagPicker as w, CommentComposer as x, CommentThread as z }; export type { AssociationCaptureToolbarProps as A, ContainerLink as B, CategorySelectProps as C, ContainerResourceRow as D, ContainerResourcesAdapter as E, PrimaryContainerEntity as G, PrimaryEntity as H, PrimaryFiledEntity as J, UseAssociationEntitySelectAdapterArgs as L, UseAssociationsArgs as M, UseAssociationsReturn as N, UseContainerLinksArgs as O, PostedComment as P, UseContainerLinksReturn as Q, TagPickerIcon as T, UniversalAssociationPickerProps as U, AssociationCardProps as a, AssociationCardGridProps as b, AssociationEntitySelectProps as c, AssociationListProps as d, AssociationWindowProps as e, AttachedItemsSheetProps as f, CategoryTagPickerProps as g, CommentThreadProps as h, AssociationCardLook as l, AssociationEntitySelectAdapter as n, AssociationEntitySelectItem as o, CaptureAttach as s, CaptureAttachResult as t, CommentComposerProps as y };