@ai-matrx/agents 0.38.3 → 0.40.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/catalog/index.cjs +3 -1
  3. package/dist/catalog/index.cjs.map +1 -1
  4. package/dist/catalog/index.d.cts +2 -2
  5. package/dist/catalog/index.d.ts +2 -2
  6. package/dist/catalog/index.js +3 -1
  7. package/dist/catalog/index.js.map +1 -1
  8. package/dist/catalog/native/index.cjs +4 -1
  9. package/dist/catalog/native/index.cjs.map +1 -1
  10. package/dist/catalog/native/index.d.cts +8 -3
  11. package/dist/catalog/native/index.d.ts +8 -3
  12. package/dist/catalog/native/index.js +4 -1
  13. package/dist/catalog/native/index.js.map +1 -1
  14. package/dist/catalog/react/index.cjs +1 -0
  15. package/dist/catalog/react/index.cjs.map +1 -1
  16. package/dist/catalog/react/index.d.cts +13 -1
  17. package/dist/catalog/react/index.d.ts +13 -1
  18. package/dist/catalog/react/index.js +1 -0
  19. package/dist/catalog/react/index.js.map +1 -1
  20. package/dist/content-transfer/index.cjs.map +1 -1
  21. package/dist/content-transfer/index.js.map +1 -1
  22. package/dist/content-transfer/react/index.cjs.map +1 -1
  23. package/dist/content-transfer/react/index.js.map +1 -1
  24. package/dist/context/index.cjs +3 -23
  25. package/dist/context/index.cjs.map +1 -1
  26. package/dist/context/index.d.cts +10 -13
  27. package/dist/context/index.d.ts +10 -13
  28. package/dist/context/index.js +5 -23
  29. package/dist/context/index.js.map +1 -1
  30. package/dist/context/react/index.cjs +263 -97
  31. package/dist/context/react/index.cjs.map +1 -1
  32. package/dist/context/react/index.d.cts +140 -15
  33. package/dist/context/react/index.d.ts +140 -15
  34. package/dist/context/react/index.js +266 -100
  35. package/dist/context/react/index.js.map +1 -1
  36. package/dist/generated/api-types.cjs.map +1 -1
  37. package/dist/generated/api-types.d.cts +1 -1
  38. package/dist/generated/api-types.d.ts +1 -1
  39. package/dist/index.cjs +6 -3
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +9 -6
  42. package/dist/index.d.ts +9 -6
  43. package/dist/index.js +6 -3
  44. package/dist/index.js.map +1 -1
  45. package/dist/{keys.generated-BdQt09qH.d.cts → keys.generated-myjGAtI0.d.cts} +4 -4
  46. package/dist/{keys.generated-BdQt09qH.d.ts → keys.generated-myjGAtI0.d.ts} +4 -4
  47. package/dist/mandates/index.cjs +2 -2
  48. package/dist/mandates/index.cjs.map +1 -1
  49. package/dist/mandates/index.d.cts +2 -2
  50. package/dist/mandates/index.d.ts +2 -2
  51. package/dist/mandates/index.js +2 -2
  52. package/dist/mandates/index.js.map +1 -1
  53. package/dist/matrx/index.d.cts +1 -1
  54. package/dist/matrx/index.d.ts +1 -1
  55. package/dist/{orchestra-zpGHwOag.d.cts → orchestra-CiaTu58J.d.cts} +7 -0
  56. package/dist/{orchestra-zpGHwOag.d.ts → orchestra-CiaTu58J.d.ts} +7 -0
  57. package/generated/api-types.ts +1 -1
  58. package/mandates/snapshots/keys.0.38.4.json +653 -0
  59. package/mandates/snapshots/keys.0.39.0.json +653 -0
  60. package/mandates/snapshots/keys.0.40.0.json +653 -0
  61. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"sources":["../../catalog/types.ts","../../catalog/ports.ts","../../catalog/store.ts","../../catalog/data.ts","../../catalog/rows.ts","../../catalog/default-row.ts","../../catalog/global-state.ts","../../catalog/schema.ts","../../catalog/orchestra.ts","../../catalog/labels.ts","../../catalog/score.ts","../../catalog/selectors.ts"],"sourcesContent":["/**\n * `@ai-matrx/agents/catalog` — the row shape and the per-consumer view state.\n *\n * `AgentSummary` is the 19-column row `agx_get_list_full()` returns, camelCased.\n * It is deliberately NOT the editable agent record: dirty tracking, undo,\n * messages, tools and `_fetchStatus` stay in whichever host owns the editor.\n * A list row is a list row.\n *\n * The view-state types are a VERBATIM port of matrx-frontend\n * `features/agents/redux/agent-consumers/slice.ts` — only the coupling seam\n * inverts (Redux reducers become store actions in `./store`).\n */\n\n/**\n * A branded agent id. Every id that reaches `onSelect` is one of these:\n * either a `agent.definition` UUID, or the `mandate:<key>` reference a\n * default row carries (byte-identical to the ref shape matrx-extend\n * `src/lib/mandates.ts` and matrx-local `desktop/src/lib/mandates.ts`\n * already hand back to their hosts).\n *\n * 🚨 The brand is a STRING LITERAL, never `unique symbol`. This package emits\n * `./catalog` and `./catalog/react` as two separate bundles, so each `.d.ts`\n * carries its own copy of these declarations. A `unique symbol` brand is\n * NOMINAL: two copies of it are unrelated types, so `createAgentCatalog()`\n * from `./catalog` was not assignable to `<AgentCatalogProvider catalog=…>`\n * from `./catalog/react` — the exact two-import wiring the README, the\n * CHANGELOG and every consumer use. A literal brand is structural, so the two\n * copies unify, while a bare `string` still cannot be passed where an\n * `AgentId` is required (which is the whole point of branding). Any future\n * brand in this package follows the same rule.\n */\nexport type AgentId = string & { readonly __agentId: \"ai-matrx.agent-id\" };\n\n/** Brand a raw string as an `AgentId`. */\nexport function asAgentId(value: string): AgentId {\n return value as AgentId;\n}\n\n/** The `mandate:<key>` ref shape every client already speaks. */\nexport function mandateAgentId(mandateKey: string): AgentId {\n return `mandate:${mandateKey}` as AgentId;\n}\n\n/** True when an id is a mandate default row rather than a stored agent. */\nexport function isMandateAgentId(id: string): boolean {\n return id.startsWith(\"mandate:\");\n}\n\n/** `agent_type` verbatim. Only `builtin` changes how a row is grouped. */\nexport type AgentCatalogAgentType = \"user\" | \"builtin\";\n\n/**\n * `access_level` verbatim from `agx_get_list_full`. Widened over the raw\n * string because it is a DB-owned vocabulary: an unknown level renders as\n * itself rather than being coerced into a wrong one.\n */\nexport type AgentAccessLevel =\n | \"owner\"\n | \"admin\"\n | \"editor\"\n | \"viewer\"\n | \"system\"\n | (string & {});\n\n/**\n * Present on a catalog row ONLY when that agent is an **Orchestra** — a\n * conductor that delegates to member agents at run time. Choosing one for a\n * step, a chat or a workflow node runs the whole ensemble, so a person has to\n * be able to SEE that before choosing, not discover it from the run.\n *\n * The DB decides. `agx_get_list_full` / `agx_get_list` / `agx_search` build\n * this from `platform.associations` (the conductor self-edge plus its member\n * edges) in one `agx_orchestra_badges()` join — never a second fetch, and\n * never a per-row read. `null` for every ordinary agent.\n *\n * History: the badge lived only in the Python `GET /agents` route, so every\n * client lost it when the pickers moved to the RPC. It is a ROW FIELD now, in\n * the one read every client shares.\n */\nexport interface OrchestraBadge {\n /** How the ensemble runs: `supervisor` | `sequential` | `parallel` | `dag`, or a future mode verbatim. */\n mode: string;\n /** The composition's one-line description, when its author wrote one. */\n tagline: string | null;\n /**\n * The per-composition delegation-depth budget AS DECLARED, or `null` when\n * the composition declares none. Deliberately NOT defaulted here: the\n * platform's fallback ceiling is enforced by the server that runs the\n * ensemble, and a badge that invented a number would be reporting a promise\n * nobody made.\n */\n depthBudget: number | null;\n /** Member edges. From the ROW count, so an unlabelled ensemble still counts. */\n memberCount: number;\n /** Only REAL role titles — an ensemble with unlabelled edges yields `[]`. */\n memberTitles: string[];\n}\n\n/**\n * One `agx_get_list_full()` row, camelCased. Nineteen columns, no more:\n * anything richer needs a different read and is a different type.\n */\nexport interface AgentSummary {\n id: AgentId;\n name: string | null;\n description: string | null;\n category: string | null;\n tags: string[];\n agentType: AgentCatalogAgentType;\n modelId: string | null;\n isActive: boolean;\n isArchived: boolean;\n isFavorite: boolean;\n createdBy: string | null;\n organizationId: string | null;\n taskId: string | null;\n sourceAgentId: string | null;\n createdAt: string | null;\n updatedAt: string | null;\n // Access metadata\n isOwner: boolean | null;\n accessLevel: AgentAccessLevel | null;\n sharedByEmail: string | null;\n /**\n * The Orchestra badge, or `null` for an ordinary agent. Strict: every row\n * carries the key, so a surface reads `agent.orchestra` and never has to ask\n * whether the column existed.\n */\n orchestra: OrchestraBadge | null;\n /**\n * Set only on a mandate default row — the key it resolved through, so a\n * host can tell \"the default\" from a stored agent without parsing the id.\n */\n mandateKey?: string;\n}\n\n// ── Per-consumer view state (verbatim port of the agent-consumers slice) ─────\n\nexport type AgentSortOption =\n | \"updated-desc\"\n | \"created-desc\"\n | \"name-asc\"\n | \"name-desc\"\n | \"category-asc\";\n\n/**\n * The sort choices a picker offers, in order. PURE DATA, so it lives in the\n * pure entry: a server-reachable manifest reads it at module scope, and\n * importing it from the client-stamped `./catalog/react` bundle dragged React\n * into a server graph for the sake of five string pairs. `./catalog/react`\n * re-exports it unchanged, so no consumer has to move.\n *\n * (Written \"client-stamped\", never with the literal directive: this comment is\n * emitted into `dist/catalog/index.d.ts`, and the tarball canary rightly\n * refuses that directive anywhere in a PURE entry.)\n */\nexport const SORT_OPTIONS: { value: AgentSortOption; label: string }[] = [\n { value: \"updated-desc\", label: \"Recent\" },\n { value: \"created-desc\", label: \"Created\" },\n { value: \"name-asc\", label: \"A → Z\" },\n { value: \"name-desc\", label: \"Z → A\" },\n { value: \"category-asc\", label: \"Category\" },\n];\n\n/** Which ownership tab is active in the agent list. */\nexport type AgentTab = \"mine\" | \"shared\" | \"all\" | \"system\";\n\n/** Favorite filter. */\nexport type AgentFavFilter = \"all\" | \"yes\" | \"no\";\n\n/**\n * The archive filter — THE ARCHIVED-ITEMS LAW's ONE control, in this\n * package's existing vocabulary.\n *\n * > \"everything should have an archive filter, and the default should always\n * > hide archived, but seeing archived items should be one or two clicks\n * > away.\" — Arman, 2026-09-09 (`common-docs/policies/archived-items.md`)\n *\n * Three states and no more, identical for every entity on the platform:\n *\n * | value | the platform's words | what the list shows |\n * |------------|----------------------|--------------------------|\n * | `active` | hide archived | only un-archived rows |\n * | `both` | show all | every row |\n * | `archived` | archived only | only archived rows |\n *\n * `active` is the platform default, and it is a KNOB — see\n * `AgentCatalogConfig.defaults.archiveFilter`.\n */\nexport type AgentArchFilter = \"active\" | \"archived\" | \"both\";\n\n/** Every legal archive-filter value, in the order the control cycles them. */\nexport const ARCHIVE_FILTER_ORDER: readonly AgentArchFilter[] = [\n \"active\",\n \"both\",\n \"archived\",\n];\n\nexport interface AgentArchFilterOption {\n value: AgentArchFilter;\n /** The platform's own words for the state — what a menu row would read. */\n label: string;\n /** What the filter-bar chip reads while this state is the active one. */\n chip: string;\n}\n\n/**\n * 🚨 ONE CONTROL, THREE STATES, SAME WORDS EVERYWHERE. A surface that invents\n * its own archive vocabulary breaks clause 3 of the law (\"the same primitive\n * everywhere … not a per-feature invention\").\n */\nexport const ARCHIVE_FILTER_OPTIONS: readonly AgentArchFilterOption[] = [\n { value: \"active\", label: \"Hide archived\", chip: \"Archive\" },\n { value: \"both\", label: \"Show all\", chip: \"All + archived\" },\n { value: \"archived\", label: \"Archived only\", chip: \"Archived only\" },\n];\n\n/**\n * The next state of the cycling control: hide archived → show all → archived\n * only → hide archived. Pure, so the web chip and the native chip cannot\n * drift apart, and so \"the control reveals archived rows in ONE action\" is a\n * testable claim rather than a UI opinion.\n */\nexport function nextArchFilter(current: AgentArchFilter): AgentArchFilter {\n const index = ARCHIVE_FILTER_ORDER.indexOf(current);\n if (index < 0) return ARCHIVE_FILTER_ORDER[0] as AgentArchFilter;\n return ARCHIVE_FILTER_ORDER[\n (index + 1) % ARCHIVE_FILTER_ORDER.length\n ] as AgentArchFilter;\n}\n\n/** True when `value` is one of the three legal states. */\nexport function isAgentArchFilter(value: unknown): value is AgentArchFilter {\n return value === \"active\" || value === \"archived\" || value === \"both\";\n}\n\n/**\n * Access level filter.\n * 'any' = no restriction (default).\n * 'owned' = only agents the user owns (isOwner = true).\n * 'shared' = only agents shared with the user (isOwner = false).\n * 'editable' = owner + admin + editor.\n */\nexport type AgentAccessFilter = \"any\" | \"owned\" | \"shared\" | \"editable\";\n\n/** Sentinel meaning \"include uncategorized / untagged\" items. */\nexport const AGENT_NONE_SENTINEL = \"__none__\";\n\nexport interface AgentConsumerState {\n tab: AgentTab;\n sortBy: AgentSortOption;\n searchTerm: string;\n\n /** INCLUSION model: empty = show all; non-empty = only matching. */\n includedCats: string[];\n\n /** INCLUSION model: empty = show all; non-empty = only matching. */\n includedTags: string[];\n\n favFilter: AgentFavFilter;\n archFilter: AgentArchFilter;\n accessFilter: AgentAccessFilter;\n favoritesFirst: boolean;\n\n /** Current page for owned-agent list items (after the card section). */\n listPage: number;\n\n /** Current page for shared-agent list items. */\n sharedPage: number;\n\n /**\n * Ids returned by the last server-side search (`agx_search`), in server rank\n * order. Additive: an agent in this list survives the search filter even\n * when the local scorer gives it 0.\n *\n * That is load-bearing for tier 2. A deep search matches an agent's prompt\n * content, which the client never loads — so the local scorer cannot see it.\n * Without this list the server would return prompt matches and the UI would\n * immediately filter them back out.\n *\n * Server-only matches sort BELOW every locally-scored match, in server rank\n * order, so obvious matches always come first.\n */\n serverMatchedIds: string[];\n\n /** True while a server search is in flight — drives the search spinner. */\n isServerSearching: boolean;\n\n /** Tier 2: also search agent prompt content. Opt-in, per consumer. */\n deepSearch: boolean;\n}\n\nexport const DEFAULT_AGENT_CONSUMER_STATE: AgentConsumerState = {\n tab: \"mine\",\n sortBy: \"updated-desc\",\n searchTerm: \"\",\n includedCats: [],\n includedTags: [],\n favFilter: \"all\",\n archFilter: \"active\",\n accessFilter: \"any\",\n favoritesFirst: true,\n listPage: 1,\n sharedPage: 1,\n serverMatchedIds: [],\n isServerSearching: false,\n deepSearch: false,\n};\n\n/** The subset of consumer state a caller may patch (paging is derived). */\nexport type AgentConsumerPatch = Partial<\n Omit<AgentConsumerState, \"listPage\" | \"sharedPage\">\n>;\n\n// ── Loud configuration failure ───────────────────────────────────────────────\n\n/**\n * Thrown by `createAgentCatalog` when a REQUIRED port is missing or an\n * optional feature was asked for without the port it needs. Never a warning,\n * never a degraded catalog: a picker that cannot read is not a picker.\n */\nexport class AgentCatalogConfigError extends Error {\n override readonly name = \"AgentCatalogConfigError\";\n /** Machine code, for a host that routes config failures. */\n readonly code: string;\n /** What the host must do, in a sentence a person can act on. */\n readonly remedy: string;\n\n constructor(args: { code: string; message: string; remedy: string }) {\n super(`${args.message} — ${args.remedy}`);\n this.code = args.code;\n this.remedy = args.remedy;\n }\n}\n","/**\n * `@ai-matrx/agents/catalog` — THE PORTS.\n *\n * Two are required (`client`, `identity`); every other one ships a working\n * default with a DOCUMENTED degradation, per THE ALL-INCLUSIVE LAW. A host\n * injects identity and a Supabase client and nothing else; the picker's only\n * contract back to the host is `onSelect(agentId)`.\n *\n * React appears nowhere in this file — it is import-inert and legal in any\n * graph, server components included.\n */\n\nimport type { AgentArchFilter, AgentSummary } from \"./types\";\n\n// ── The data seam ────────────────────────────────────────────────────────────\n\n/** A PostgREST error, structurally. */\nexport interface PgErrorLike {\n message: string;\n code?: string;\n details?: string | null;\n hint?: string | null;\n}\n\n/** What every supabase-js call resolves to, structurally. */\nexport interface PgResultLike {\n data: unknown;\n error: PgErrorLike | null;\n count?: number | null;\n}\n\n/**\n * The thenable builder supabase-js returns from `.rpc()`. `range` is what\n * makes a COMPLETE list read possible (`readAllRows`); `order` is what makes\n * that paging stable. Both are the real builder's own methods — this is a\n * structural subset, never a re-implementation.\n */\nexport interface AgentCatalogRpcCall extends PromiseLike<PgResultLike> {\n range(from: number, to: number): PromiseLike<PgResultLike>;\n order(column: string, options?: { ascending?: boolean }): AgentCatalogRpcCall;\n}\n\n/**\n * REQUIRED. A structural subset of `SupabaseClient` — anything that can answer\n * `agx_get_list_full`, `agx_search` and `agx_resolve_agent_address`. A real\n * supabase-js client satisfies it as-is. (It is also the data source the\n * DEFAULT favorites port is built on — see `AgentCatalogFavorites`.)\n *\n * Absent → `createAgentCatalog` throws `AgentCatalogConfigError`. There is no\n * degraded mode: the package IS the catalogue read.\n */\nexport interface AgentCatalogClient {\n rpc(\n fn: string,\n args?: Record<string, unknown>,\n options?: { count?: \"exact\" | \"planned\" | \"estimated\" },\n ): AgentCatalogRpcCall;\n}\n\n/**\n * A star is PER-PERSON state and lives in `platform.user_entity_state` — never\n * a column on `agent.definition` (the retired `is_favorite` flag sat on the\n * OWNER's row, so a shared agent could not be starred and two surfaces drifted).\n *\n * This is the structural subset of `@ai-matrx/associations/core`'s\n * `FavoritesServiceApi` the catalog uses — the platform's ONE `ues_*`\n * chokepoint. Results never throw; a refusal comes back as `{ ok: false }`.\n *\n * OPTIONAL. DEFAULT: `createAssociationsStore({ dataSource: client, identity,\n * errorSink }).favorites` — the same chokepoint, built on the same client. A\n * host that already holds a favorites service (matrx-frontend's\n * `favoritesService`) passes it so there is exactly one instance.\n */\nexport interface AgentCatalogFavorites {\n getBulk(\n entityType: string,\n entityIds: string[],\n ): Promise<\n | { ok: true; data: { items: { entityId: string; isFavorite: boolean }[] } }\n | { ok: false; error: { message: string; code?: string } }\n >;\n setFavorite(\n entityType: string,\n entityId: string,\n isFavorite: boolean,\n ): Promise<\n | { ok: true; data: unknown }\n | { ok: false; error: { message: string; code?: string } }\n >;\n}\n\n/**\n * REQUIRED. Who is asking. Needed for the \"zero owned agents → open on the\n * public tab\" heuristic and for the favorites port.\n *\n * `requireUserId` THROWS when there is no session — never a silent anonymous\n * read. The catalog catches that throw in exactly ONE place (the tab-default\n * heuristic, where a signed-out visitor legitimately lands on the public\n * catalogue) and reports it to the `errorSink` the first time; every other\n * caller lets it propagate.\n */\nexport interface AgentCatalogIdentity {\n requireUserId(): string;\n /**\n * OPTIONAL non-throwing twin: the signed-in user id, or `null` for a\n * signed-out visitor. When bound, `null` is a legitimate STATE (a guest\n * page), not a failure — nothing is reported. Bind it whenever the host can\n * tell \"no session\" apart from \"identity is broken\".\n */\n getUserId?(): string | null;\n}\n\n// ── Optional ports, each with a documented degradation ───────────────────────\n\n/**\n * Every degraded path, every failed read, every drift detection reports here.\n * DEFAULT: a tagged `console.error` that announces ONCE that no sink is bound\n * and names the remedy.\n */\nexport type AgentCatalogErrorSink = (event: {\n code: string;\n message: string;\n context?: object;\n}) => void;\n\n/**\n * The drift scream's second channel. DEFAULT: none — and that is safe\n * ONLY because the in-picker persistent banner is the primary scream and\n * always renders. A drift is never console-only.\n */\nexport type AgentCatalogNotifier = (event: {\n level: \"warning\" | \"error\";\n title: string;\n message: string;\n}) => void;\n\n/**\n * First-paint cache for resolved default rows. DEFAULT: `localStorage` when\n * present, else an in-memory map (so SSR and a Chrome service worker both\n * work). Absent storage degrades to \"no first paint of the default row until\n * the mandate resolves\" — never a wrong name on screen.\n */\nexport interface AgentCatalogStorage {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\n/**\n * The SAME seam for a platform whose only key-value store is asynchronous.\n *\n * 🚨 WHY THIS EXISTS (0.9.0). React Native has no `localStorage`; every Expo\n * app's store (`@react-native-async-storage/async-storage`, `expo-secure-store`,\n * MMKV's async face) answers with a promise. Before this, a native host had\n * exactly two options — hand the package a storage that lies by returning\n * `null` synchronously, or lose the default row's first paint entirely. Both\n * are the silent degradation this package exists to refuse.\n *\n * The shape is `AsyncStorage`'s own, so an Expo host passes AsyncStorage\n * directly with no adapter. Every method may answer synchronously OR with a\n * promise, which is what makes `AgentCatalogStorage` a subtype of this one:\n * the WEB PATH IS UNCHANGED — a sync storage still resolves in the same\n * microtask, and `readCachedDefaultRow`/`writeCachedDefaultRow` keep their\n * synchronous signatures for every existing caller.\n */\nexport interface AgentCatalogAsyncStorage {\n getItem(key: string): string | null | Promise<string | null>;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\n/** Either storage shape. What `AgentCatalogConfig.storage` accepts. */\nexport type AgentCatalogStorageLike =\n | AgentCatalogStorage\n | AgentCatalogAsyncStorage;\n\n/** Every user-visible string the picker renders, overridable per host. */\nexport interface AgentCatalogLabels {\n /** User-facing label for the `system` ownership tab. */\n publicTab: string;\n /**\n * Badge label on a builtin row. Default `\"system\"` — the string\n * `AgentRow` actually rendered in matrx-frontend. (The frontend also\n * declared `AGENT_PUBLIC_BADGE_LABEL = \"Public\"` for this badge and NOTHING\n * ever read it — a constant that named the badge without being the badge.\n * Recorded in the CHANGELOG and dropped rather than ported.)\n */\n systemBadge: string;\n /**\n * Badge on an archived row. Archived agents stay offered (THE ARCHIVED-ITEMS\n * LAW: one or two clicks away) and say so on the row itself. Default\n * `\"Archived\"`.\n */\n archivedBadge: string;\n searchPlaceholder: string;\n currentAgentHeading: string;\n emptyDefault: string;\n emptyShared: string;\n emptySystem: string;\n /** Empty state for a signed-out visitor — there is no catalogue to read. */\n emptySignedOut: string;\n loading: string;\n triggerFallback: string;\n triggerResolving: string;\n triggerUnnameable: string;\n hoverHint: string;\n}\n\nexport const DEFAULT_AGENT_CATALOG_LABELS: AgentCatalogLabels = {\n publicTab: \"Public\",\n systemBadge: \"system\",\n archivedBadge: \"Archived\",\n searchPlaceholder: \"Search agents...\",\n currentAgentHeading: \"Current agent\",\n emptyDefault: \"No agents found\",\n emptyShared: \"No shared agents found\",\n emptySystem: \"No system agents found\",\n emptySignedOut: \"Sign in to see your agents\",\n loading: \"Loading...\",\n triggerFallback: \"Agents\",\n triggerResolving: \"Naming the agent…\",\n triggerUnnameable: \"An agent this list cannot name\",\n hoverHint: \"Hover an agent to preview its details, or click to select.\",\n};\n\n// ── The core config ──────────────────────────────────────────────────────────\n\nexport interface AgentCatalogConfig {\n /** REQUIRED — the Supabase client. */\n client: AgentCatalogClient;\n /** REQUIRED — who is asking. */\n identity: AgentCatalogIdentity;\n /** OPTIONAL — see `AgentCatalogFavorites`. */\n favorites?: AgentCatalogFavorites;\n /**\n * The catalog's registry key on `globalThis`. Two `createAgentCatalog`\n * calls with the same id are the same catalog (and the second one screams\n * through the errorSink before replacing the first). Default `\"default\"`.\n */\n catalogId?: string;\n /** OPTIONAL — see `AgentCatalogErrorSink`. */\n errorSink?: AgentCatalogErrorSink;\n /** OPTIONAL — see `AgentCatalogNotifier`. */\n notifier?: AgentCatalogNotifier;\n /**\n * OPTIONAL — see `AgentCatalogStorage` and `AgentCatalogAsyncStorage`. A\n * synchronous store (the web `localStorage` default) and an asynchronous\n * one (React Native's `AsyncStorage`) are both accepted verbatim.\n */\n storage?: AgentCatalogStorageLike;\n /**\n * OPTIONAL — the package's own `MatrxTransport` (`createMatrxTransport`\n * from `@ai-matrx/agents/matrx`). REQUIRED the moment any picker instance\n * passes a `defaultMandateKey`: THE PLATFORM RULE D-R1 says clients never\n * walk the mandate ladder, so the default row can only be resolved through\n * the aidream door `GET /mandates/{mandate_key}/resolution`. A\n * `defaultMandateKey` with no transport throws `AgentCatalogConfigError`.\n */\n transport?: AgentCatalogTransport;\n /** OPTIONAL — label overrides. */\n labels?: Partial<AgentCatalogLabels>;\n /**\n * OPTIONAL — the host's starting values for per-consumer view state.\n * See `AgentCatalogDefaults`.\n */\n defaults?: AgentCatalogDefaults;\n}\n\n/**\n * 🚨 OPINIONS BECOME KNOBS (root law 6). The archive filter's initial state is\n * a configurable default, not code taste — clause 6 of THE ARCHIVED-ITEMS LAW\n * (`common-docs/policies/archived-items.md`) says so explicitly.\n *\n * The PLATFORM default is `\"active\"` (hide archived) and a host that passes\n * nothing gets exactly that. A host wires this to whatever its org/user\n * setting resolves to; an individual picker can still override it per\n * consumer (`useAgentListCore({ initialArchFilter })`), and the person can\n * always change it from the control on the filter bar.\n *\n * An illegal value is NOT coerced to the default — it throws\n * `AgentCatalogConfigError`, because a silently-ignored setting is a knob that\n * lies about being a knob.\n */\nexport interface AgentCatalogDefaults {\n archiveFilter?: AgentArchFilter;\n}\n\n/**\n * The transport seam, structurally identical to `MatrxTransport` from\n * `@ai-matrx/agents/matrx` (declared structurally so `./catalog` never\n * imports the transport module and stays import-inert).\n */\nexport interface AgentCatalogTransport {\n fetch(\n path: string,\n init: {\n method: \"GET\" | \"POST\";\n headers: Record<string, string>;\n body?: string;\n signal?: AbortSignal;\n },\n ): Promise<Response>;\n}\n\n// ── React-layer ports (bound on the provider, never on the headless core) ────\n\n/**\n * Where a row's href goes when someone cmd-clicks it, and where `navigateTo`\n * lands. DEFAULT: `window.location.assign` (so cmd-click and ordinary\n * navigation both work with no host wiring at all).\n */\nexport type AgentCatalogNavigate = (href: string) => void;\n\n/** Resolve a per-row href. DEFAULT: `/agents/go/<id>` — the always-valid door. */\nexport type AgentCatalogResolveHref = (agent: AgentSummary) => string;\n\n/**\n * The sneak-peek affordance. Absent → the affordance is HIDDEN, never a dead\n * button (nothing fails silently, and nothing looks alive when it is not).\n */\nexport type AgentCatalogOpenPeek = (agent: AgentSummary) => void;\n","/**\n * catalog/store.ts — @ai-matrx/agents/catalog\n *\n * `createAgentCatalog(config)` — the headless kernel. Everything the picker\n * knows lives here: the row registry, the complete-list read with its\n * session-shared in-flight dedupe and freshness window, the tier-2 server\n * search, the per-consumer view state, the ONE write, and the mandate default\n * row with its drift screamer.\n *\n * The host injects a Supabase client and who the user is. Nothing else.\n *\n * The consumer reducers below are a VERBATIM port of matrx-frontend\n * `features/agents/redux/agent-consumers/slice.ts`; only the seam inverts\n * (a Redux reducer becomes a store method, and Immer's draft mutation becomes\n * an explicit copy so the store can publish a new reference).\n */\n\nimport { createAssociationsStore } from \"@ai-matrx/associations/core\";\n\nimport {\n overlayAgentFavorites,\n readAgentCatalogRows,\n searchAgentsOnServer,\n writeAgentFavorite,\n} from \"./data\";\nimport type { DefaultRowState } from \"./default-row-types\";\nimport {\n defaultStorage,\n MandateDefaultRowError,\n resolveDefaultRow,\n} from \"./default-row\";\nimport { getCatalogGlobalState } from \"./global-state\";\nimport {\n DEFAULT_AGENT_CATALOG_LABELS,\n type AgentCatalogConfig,\n type AgentCatalogErrorSink,\n type AgentCatalogFavorites,\n type AgentCatalogLabels,\n type AgentCatalogNotifier,\n type AgentCatalogStorageLike,\n} from \"./ports\";\nimport {\n assertAgentCatalogSchema,\n type AgentCatalogSchemaReport,\n type AssertAgentCatalogSchemaOptions,\n} from \"./schema\";\nimport {\n AgentCatalogConfigError,\n DEFAULT_AGENT_CONSUMER_STATE,\n isAgentArchFilter,\n type AgentConsumerPatch,\n type AgentConsumerState,\n type AgentSummary,\n} from \"./types\";\n\n/**\n * Module-level TTL guard, ported from matrx-frontend's `_chatListFetchedAt`.\n * Deliberately NOT view state: it is a session-local guard, not something a\n * person sees. It lives on `globalThis` — see `global-state.ts`.\n */\nconst LIST_TTL_MS = 15 * 60 * 1000; // 15 minutes\nconst LIST_STALE_MS = 4 * 60 * 60 * 1000; // 4 hours — tab-restore threshold\n\nexport type AgentCatalogStatus = \"idle\" | \"loading\" | \"succeeded\" | \"failed\";\n\nexport interface AgentCatalogState {\n /** Every row, one stable array reference per change (memoization depends on it). */\n rows: AgentSummary[];\n byId: Record<string, AgentSummary>;\n status: AgentCatalogStatus;\n error: string | null;\n consumers: Record<string, AgentConsumerState>;\n /** Keyed by mandate key. */\n defaultRows: Record<string, DefaultRowState>;\n}\n\nexport interface AgentCatalog {\n readonly catalogId: string;\n readonly labels: AgentCatalogLabels;\n readonly errorSink: AgentCatalogErrorSink;\n readonly notifier: AgentCatalogNotifier | undefined;\n /** True when this catalog was given a transport and can resolve mandates. */\n readonly canResolveMandates: boolean;\n /**\n * The consumer state a brand-new consumer starts from, AFTER the host's\n * `defaults` knob is applied. Read it instead of\n * `DEFAULT_AGENT_CONSUMER_STATE` whenever the question is \"is this filter at\n * its default?\" — a host that legitimately defaults the archive filter to\n * \"show all\" must not have every control render as though it were modified.\n */\n readonly consumerDefaults: AgentConsumerState;\n\n getState(): AgentCatalogState;\n subscribe(listener: () => void): () => void;\n\n getAgent(agentId: string): AgentSummary | undefined;\n /**\n * The signed-in user id, or `null` when there is no session. The ONE place\n * `identity.requireUserId()`'s throw is caught — a signed-out visitor\n * legitimately lands on the public catalogue — and it is reported to the\n * errorSink the first time so it is never silent.\n */\n getUserIdOrNull(): string | null;\n\n /** Load the catalogue if it is not fresh. Safe to call on every mount. */\n ensureLoaded(options?: { force?: boolean }): Promise<void>;\n /** True when the last load is inside the 15-minute TTL. */\n isFresh(): boolean;\n /** True when the last load is older than 4 hours (tab-restore threshold). */\n isStale(): boolean;\n\n getConsumer(consumerId: string): AgentConsumerState;\n registerConsumer(consumerId: string, initial?: AgentConsumerPatch): void;\n unregisterConsumer(consumerId: string): void;\n setConsumerFilter(consumerId: string, patch: AgentConsumerPatch): void;\n setConsumerPage(\n consumerId: string,\n which: \"list\" | \"shared\",\n page: number,\n ): void;\n setConsumerServerSearch(\n consumerId: string,\n args: { matchedIds?: string[]; isSearching?: boolean },\n ): void;\n resetConsumerFilters(consumerId: string): void;\n\n /** Tier-2 search. Purely additive; merges rows into the registry. */\n searchServer(query: string, deep?: boolean): Promise<string[]>;\n\n /** THE ONE WRITE. Optimistic, rolled back on failure, loud either way. */\n setFavorite(agentId: string, isFavorite: boolean): Promise<void>;\n\n /** Resolve (once) the default row for a mandate key. Idempotent. */\n ensureDefaultRow(mandateKey: string): void;\n getDefaultRow(mandateKey: string): DefaultRowState | undefined;\n /** A person acknowledged the drift banner. The notifier already fired. */\n dismissDefaultRowDrift(mandateKey: string): void;\n /** Re-ask the mandate door for a row that refused (see ensureDefaultRow). */\n retryDefaultRow(mandateKey: string): void;\n\n assertSchema(\n options?: AssertAgentCatalogSchemaOptions,\n ): Promise<AgentCatalogSchemaReport>;\n}\n\n/** DEFAULT error sink: a tagged console.error that names the remedy once. */\nfunction createDefaultErrorSink(): AgentCatalogErrorSink {\n let announced = false;\n return (event) => {\n if (!announced) {\n announced = true;\n // eslint-disable-next-line no-console\n console.error(\n \"[@ai-matrx/agents/catalog] no errorSink is bound, so failures are \" +\n \"only reaching the console. Pass `errorSink` to createAgentCatalog \" +\n \"to route them into your diagnostics surface.\",\n );\n }\n // eslint-disable-next-line no-console\n console.error(`[@ai-matrx/agents/catalog] ${event.code}: ${event.message}`, {\n ...(event.context ?? {}),\n });\n };\n}\n\nfunction errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\nexport function createAgentCatalog(config: AgentCatalogConfig): AgentCatalog {\n if (!config || typeof config !== \"object\") {\n throw new AgentCatalogConfigError({\n code: \"missing_config\",\n message: \"createAgentCatalog was called without a config object\",\n remedy: \"pass { client, identity }\",\n });\n }\n if (!config.client || typeof config.client.rpc !== \"function\") {\n throw new AgentCatalogConfigError({\n code: \"missing_client\",\n message:\n \"createAgentCatalog needs a Supabase client — it IS the catalogue read\",\n remedy:\n \"pass `client` (a supabase-js client, or anything with rpc() and schema().from())\",\n });\n }\n if (!config.identity || typeof config.identity.requireUserId !== \"function\") {\n throw new AgentCatalogConfigError({\n code: \"missing_identity\",\n message: \"createAgentCatalog needs to know who is asking\",\n remedy: \"pass `identity: { requireUserId() }` — never a silent anonymous read\",\n });\n }\n\n const archiveDefault = config.defaults?.archiveFilter;\n if (archiveDefault !== undefined && !isAgentArchFilter(archiveDefault)) {\n // A knob that silently ignores its value is worse than no knob: the host\n // believes the setting took effect and the screen disagrees.\n throw new AgentCatalogConfigError({\n code: \"invalid_archive_default\",\n message:\n `defaults.archiveFilter was ${JSON.stringify(archiveDefault)}, which ` +\n \"is not one of the three states of the platform archive filter\",\n remedy:\n 'pass \"active\" (hide archived), \"both\" (show all) or \"archived\" (archived only)',\n });\n }\n\n /**\n * 🚨 THE ARCHIVED-ITEMS LAW's knob, resolved ONCE. Everything below that\n * needs a starting consumer state reads this, never\n * `DEFAULT_AGENT_CONSUMER_STATE` — so the platform default (\"hide archived\")\n * and a host's override travel the same single path into every consumer,\n * every reset and every \"is this at its default?\" comparison.\n */\n const consumerDefaults: AgentConsumerState = {\n ...DEFAULT_AGENT_CONSUMER_STATE,\n ...(archiveDefault ? { archFilter: archiveDefault } : {}),\n };\n\n const catalogId = config.catalogId ?? \"default\";\n const client = config.client;\n const identity = config.identity;\n const errorSink = config.errorSink ?? createDefaultErrorSink();\n const notifier = config.notifier;\n const storage: AgentCatalogStorageLike = config.storage ?? defaultStorage();\n const transport = config.transport;\n /**\n * Stars live in `platform.user_entity_state`, reached only through the\n * platform's ONE `ues_*` chokepoint. A host that already holds it passes it;\n * otherwise the same chokepoint is built here on the same client.\n */\n const favorites: AgentCatalogFavorites =\n config.favorites ??\n createAssociationsStore({\n // The catalog's client IS a supabase-js client; the associations\n // data-source port is the same `rpc(fn, args)` shape, typed over its\n // own demanded-RPC names.\n dataSource: client as unknown as Parameters<\n typeof createAssociationsStore\n >[0][\"dataSource\"],\n identity,\n errorSink,\n }).favorites;\n function reportFavoriteReadFailure(message: string): void {\n errorSink({\n code: \"favorite_read_failed\",\n message:\n `your starred agents could not be read (${message}); every star is ` +\n \"shown unset until the next catalogue load\",\n context: { catalogId },\n });\n }\n const labels: AgentCatalogLabels = {\n ...DEFAULT_AGENT_CATALOG_LABELS,\n ...(config.labels ?? {}),\n };\n\n const globalState = getCatalogGlobalState();\n if (globalState.catalogs.has(catalogId)) {\n errorSink({\n code: \"catalog_replaced\",\n message:\n `a second agent catalog was created under id \"${catalogId}\" and has ` +\n \"REPLACED the first. Two catalogs with one id share a freshness stamp \" +\n \"and an in-flight promise; give each one its own `catalogId`.\",\n });\n }\n\n let state: AgentCatalogState = {\n rows: [],\n byId: {},\n status: \"idle\",\n error: null,\n consumers: {},\n defaultRows: {},\n };\n\n const listeners = new Set<() => void>();\n function publish(next: AgentCatalogState): void {\n state = next;\n for (const listener of listeners) listener();\n }\n\n // ── The row registry ──────────────────────────────────────────────────────\n\n /** Additive merge — a search hit never removes a row already on screen. */\n function mergeRows(incoming: AgentSummary[]): void {\n if (incoming.length === 0) return;\n const byId = { ...state.byId };\n for (const row of incoming) byId[row.id] = row;\n publish({ ...state, byId, rows: Object.values(byId) });\n }\n\n function replaceRows(incoming: AgentSummary[]): void {\n const byId: Record<string, AgentSummary> = {};\n for (const row of incoming) byId[row.id] = row;\n publish({ ...state, byId, rows: Object.values(byId) });\n }\n\n // ── Identity ──────────────────────────────────────────────────────────────\n\n let anonymousReported = false;\n function getUserIdOrNull(): string | null {\n // A host that can say \"no session\" without throwing has told us a\n // signed-out visitor is a STATE, not a broken identity — never reported.\n if (typeof identity.getUserId === \"function\") return identity.getUserId();\n try {\n return identity.requireUserId();\n } catch (e) {\n if (!anonymousReported) {\n anonymousReported = true;\n errorSink({\n code: \"identity_unavailable\",\n message:\n \"identity.requireUserId() threw, so the picker is treating this \" +\n \"session as signed out and opening on the public catalogue. \" +\n \"Favoriting is unavailable until a session exists.\",\n context: { detail: errorMessage(e) },\n });\n }\n return null;\n }\n }\n\n // ── The complete-list read ───────────────────────────────────────────────\n\n function isFresh(): boolean {\n const at = globalState.listFetchedAt.get(catalogId);\n if (at === undefined) return false;\n return Date.now() - at < LIST_TTL_MS;\n }\n\n function isStale(): boolean {\n const at = globalState.listFetchedAt.get(catalogId);\n if (at === undefined) return true;\n return Date.now() - at > LIST_STALE_MS;\n }\n\n async function load(): Promise<void> {\n // A signed-out visitor HAS no catalogue: `agx_get_list_full` is not\n // executable by `anon`, so the read could only come back 42501 and land\n // as a captured error on every guest page that mounts a picker (live\n // 2026-10-01). Answer the empty catalogue instead, and do NOT stamp\n // freshness — the first `ensureLoaded` after sign-in reads for real.\n if (getUserIdOrNull() === null) {\n if (state.rows.length > 0) replaceRows([]);\n publish({ ...state, status: \"succeeded\", error: null });\n return;\n }\n publish({ ...state, status: \"loading\", error: null });\n try {\n const rows = await overlayAgentFavorites(\n favorites,\n await readAgentCatalogRows(client),\n reportFavoriteReadFailure,\n );\n replaceRows(rows);\n publish({ ...state, status: \"succeeded\", error: null });\n globalState.listFetchedAt.set(catalogId, Date.now());\n } catch (e) {\n const message = errorMessage(e);\n publish({ ...state, status: \"failed\", error: message });\n errorSink({\n code: \"list_read_failed\",\n message: `the agent catalogue could not be read: ${message}`,\n context: { catalogId },\n });\n throw e;\n }\n }\n\n async function ensureLoaded(options?: { force?: boolean }): Promise<void> {\n const force = options?.force ?? false;\n if (!force && isFresh()) return;\n\n // In-flight dedupe (ported verbatim in intent from `_listFullInFlight`):\n // ~20 surfaces call this on mount and several co-exist on one page, with\n // their effects running in the same commit — no component-level or\n // status-based guard can see a sibling's request. Sharing the promise\n // collapses them to ONE read while every caller still awaits a real result.\n const existing = globalState.listInFlight.get(catalogId);\n if (existing) return existing;\n\n const run = load().finally(() => {\n if (globalState.listInFlight.get(catalogId) === run) {\n globalState.listInFlight.delete(catalogId);\n }\n });\n globalState.listInFlight.set(catalogId, run);\n // A rejected shared promise must not become an unhandled rejection for\n // the siblings that merely awaited it — every caller sees the throw.\n return run;\n }\n\n // ── Per-consumer view state (verbatim reducer bodies) ────────────────────\n\n function getConsumer(consumerId: string): AgentConsumerState {\n return state.consumers[consumerId] ?? consumerDefaults;\n }\n\n function writeConsumer(consumerId: string, next: AgentConsumerState): void {\n publish({\n ...state,\n consumers: { ...state.consumers, [consumerId]: next },\n });\n }\n\n function registerConsumer(\n consumerId: string,\n initial?: AgentConsumerPatch,\n ): void {\n // Idempotent — safe on every mount; never resets an existing consumer.\n if (state.consumers[consumerId]) return;\n writeConsumer(consumerId, {\n ...consumerDefaults,\n ...(initial ?? {}),\n });\n }\n\n function unregisterConsumer(consumerId: string): void {\n if (!state.consumers[consumerId]) return;\n const consumers = { ...state.consumers };\n delete consumers[consumerId];\n publish({ ...state, consumers });\n }\n\n function setConsumerFilter(\n consumerId: string,\n patch: AgentConsumerPatch,\n ): void {\n const current = state.consumers[consumerId] ?? { ...consumerDefaults };\n // Paging always resets so nobody is stranded on a page with no results.\n writeConsumer(consumerId, {\n ...current,\n ...patch,\n listPage: 1,\n sharedPage: 1,\n });\n }\n\n function setConsumerPage(\n consumerId: string,\n which: \"list\" | \"shared\",\n page: number,\n ): void {\n const current = state.consumers[consumerId];\n if (!current) return;\n writeConsumer(\n consumerId,\n which === \"list\"\n ? { ...current, listPage: page }\n : { ...current, sharedPage: page },\n );\n }\n\n function setConsumerServerSearch(\n consumerId: string,\n args: { matchedIds?: string[]; isSearching?: boolean },\n ): void {\n const current = state.consumers[consumerId] ?? { ...consumerDefaults };\n // Deliberately does NOT reset pagination: server results arrive after the\n // user already typed, and yanking them to page 1 mid-scroll is its own bug.\n const next: AgentConsumerState = { ...current };\n if (args.matchedIds !== undefined) next.serverMatchedIds = args.matchedIds;\n if (args.isSearching !== undefined) next.isServerSearching = args.isSearching;\n if (\n next.serverMatchedIds === current.serverMatchedIds &&\n next.isServerSearching === current.isServerSearching\n ) {\n return;\n }\n writeConsumer(consumerId, next);\n }\n\n function resetConsumerFilters(consumerId: string): void {\n if (!state.consumers[consumerId]) return;\n writeConsumer(consumerId, { ...consumerDefaults });\n }\n\n // ── Tier-2 server search ─────────────────────────────────────────────────\n\n async function searchServer(query: string, deep = false): Promise<string[]> {\n const result = await searchAgentsOnServer(client, { query, deep });\n mergeRows(\n await overlayAgentFavorites(\n favorites,\n result.rows,\n reportFavoriteReadFailure,\n ),\n );\n return result.ids;\n }\n\n // ── THE ONE WRITE ────────────────────────────────────────────────────────\n\n async function setFavorite(\n agentId: string,\n isFavorite: boolean,\n ): Promise<void> {\n const existing = state.byId[agentId];\n if (!existing) {\n errorSink({\n code: \"favorite_unknown_agent\",\n message: `cannot favorite ${agentId}: it is not in this catalogue`,\n });\n return;\n }\n // Optimistic.\n mergeRows([{ ...existing, isFavorite }]);\n try {\n await writeAgentFavorite(favorites, agentId, isFavorite);\n } catch (e) {\n // Rollback, then SCREAM. A star that silently springs back is a lie.\n mergeRows([existing]);\n errorSink({\n code: \"favorite_write_failed\",\n message: `the favorite could not be saved: ${errorMessage(e)}`,\n context: { agentId, isFavorite },\n });\n notifier?.({\n level: \"error\",\n title: \"Favorite not saved\",\n message:\n \"The star was put back because the change could not be saved. \" +\n \"Check your connection and try again.\",\n });\n throw e;\n }\n }\n\n // ── The mandate default row ──────────────────────────────────────────────\n\n function writeDefaultRow(mandateKey: string, next: DefaultRowState): void {\n publish({\n ...state,\n defaultRows: { ...state.defaultRows, [mandateKey]: next },\n });\n }\n\n const defaultRowsInFlight = new Set<string>();\n\n function ensureDefaultRow(mandateKey: string): void {\n if (!mandateKey) return;\n if (defaultRowsInFlight.has(mandateKey)) return;\n // 🚨 A REFUSAL IS A STATE TO LEAVE, NOT A PLACE TO LIVE. Until 0.13.0 an\n // errored row was cached exactly like a resolved one, so ONE transient\n // refusal (matrx-extend, 2026-09-19: the door was asked a beat before the\n // bearer was readable and answered 401) pinned \"the server refused to\n // resolve it\" on the picker for the rest of the session. A resolved row is\n // still asked once; an errored row is re-asked whenever a surface asks\n // again, because the caller's session, organization or network may have\n // changed since the refusal.\n const current = state.defaultRows[mandateKey];\n if (current && !current.error) return;\n if (!transport) {\n // Loud, typed, and at the moment it is asked for — never a blank row.\n throw new AgentCatalogConfigError({\n code: \"missing_transport\",\n message:\n `a picker asked for the default row of mandate \"${mandateKey}\", but ` +\n \"this catalog has no transport\",\n remedy:\n \"pass `transport` (createMatrxTransport from @ai-matrx/agents/matrx) \" +\n \"to createAgentCatalog — clients never walk the mandate ladder \" +\n \"themselves, they ask the server\",\n });\n }\n defaultRowsInFlight.add(mandateKey);\n writeDefaultRow(mandateKey, {\n mandateKey,\n row: null,\n resolved: null,\n loading: true,\n drift: null,\n error: null,\n });\n\n void (async () => {\n try {\n const outcome = await resolveDefaultRow({\n mandateKey,\n transport,\n client,\n storage,\n errorSink,\n lookupRow: async (id) => {\n const hit = state.byId[id];\n if (hit) return hit;\n const inFlight = globalState.listInFlight.get(catalogId);\n if (!inFlight) return undefined;\n // A failed list read already screamed through its own path;\n // here it only means \"not in the catalogue\".\n await inFlight.catch(() => undefined);\n return state.byId[id];\n },\n });\n getCatalogGlobalState().defaultRows.set(\n `${catalogId}::${mandateKey}`,\n outcome.resolved,\n );\n writeDefaultRow(mandateKey, {\n mandateKey,\n row: outcome.row,\n resolved: outcome.resolved,\n loading: false,\n drift: outcome.drift,\n error: null,\n });\n if (outcome.drift) {\n // 🚨 THE DRIFT SCREAM — the banner above is the primary channel and\n // always renders; the notifier and the sink are additional, never a\n // substitute, and this is never console-only.\n errorSink({\n code: \"default_row_drift\",\n message: outcome.drift,\n context: { mandateKey, holderId: outcome.resolved.holderId },\n });\n notifier?.({\n level: \"warning\",\n title: \"The default agent changed\",\n message: outcome.drift,\n });\n }\n } catch (e) {\n const message =\n e instanceof MandateDefaultRowError ? e.message : errorMessage(e);\n writeDefaultRow(mandateKey, {\n mandateKey,\n row: null,\n resolved: null,\n loading: false,\n drift: null,\n error: message,\n });\n errorSink({\n code: \"default_row_unresolved\",\n message,\n context: { mandateKey },\n });\n } finally {\n defaultRowsInFlight.delete(mandateKey);\n }\n })();\n }\n\n function getDefaultRow(mandateKey: string): DefaultRowState | undefined {\n return state.defaultRows[mandateKey];\n }\n\n function dismissDefaultRowDrift(mandateKey: string): void {\n const current = state.defaultRows[mandateKey];\n if (!current || !current.drift) return;\n writeDefaultRow(mandateKey, { ...current, drift: null });\n }\n\n /**\n * Ask the mandate door again for a row that refused. The errored row is\n * dropped first so the picker shows the in-flight state instead of the old\n * refusal, and an in-flight ask is never doubled.\n */\n function retryDefaultRow(mandateKey: string): void {\n if (!mandateKey || defaultRowsInFlight.has(mandateKey)) return;\n const { [mandateKey]: _dropped, ...rest } = state.defaultRows;\n publish({ ...state, defaultRows: rest });\n ensureDefaultRow(mandateKey);\n }\n\n const catalog: AgentCatalog = {\n catalogId,\n labels,\n errorSink,\n notifier,\n canResolveMandates: transport !== undefined,\n consumerDefaults,\n getState: () => state,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n getAgent: (agentId) => state.byId[agentId],\n getUserIdOrNull,\n ensureLoaded,\n isFresh,\n isStale,\n getConsumer,\n registerConsumer,\n unregisterConsumer,\n setConsumerFilter,\n setConsumerPage,\n setConsumerServerSearch,\n resetConsumerFilters,\n searchServer,\n setFavorite,\n ensureDefaultRow,\n getDefaultRow,\n dismissDefaultRowDrift,\n retryDefaultRow,\n assertSchema: (options) => assertAgentCatalogSchema(client, options),\n };\n\n globalState.catalogs.set(catalogId, catalog);\n return catalog;\n}\n\n/**\n * The catalog registered under `catalogId`, across loader graphs. Returns\n * `undefined` when none has been created yet — never a silent stub.\n */\nexport function getRegisteredAgentCatalog(\n catalogId = \"default\",\n): AgentCatalog | undefined {\n const found = getCatalogGlobalState().catalogs.get(catalogId);\n return found as AgentCatalog | undefined;\n}\n","/**\n * catalog/data.ts — @ai-matrx/agents/catalog\n *\n * Every database call the catalog makes, and nothing else. Five of them:\n *\n * 1. `agx_get_list_full()` — the complete catalogue (owned + directly-shared\n * + org-shared user agents, unioned with active builtins).\n * 2. `agx_search(p_query, p_deep, p_limit, p_offset)` — tier-2 server search.\n * 3. `agx_resolve_agent_address(p_ids)` — the single-agent name read, used\n * when a mandate's Holder is not in the caller's own catalogue.\n * 4. The caller's stars: `ues_get_bulk('agent', ids)` through the\n * favorites port (`platform.user_entity_state`), overlaid on every row\n * set this module returns to the store.\n * 5. ONE write: the caller's star, `ues_set` through the same port. The\n * retired `agent.definition.is_favorite` column is never read or written.\n *\n * 🚨 THE LIST READ IS COMPLETE OR IT THROWS. PostgREST caps every response at\n * `db-max-rows` (1000 on Matrx Main) and reports success — matrx-frontend's\n * `fetchAgentsListFull` issued a bare `.rpc()` and would silently have\n * returned 1000 rows of a larger catalogue (the ~400-builtin truncation\n * incident is the near-miss). Here the read goes through `readAllRows` with\n * `{ count: \"exact\" }` and a stable `.order(\"id\")`, so a truncation is a\n * loud `IncompleteReadError` instead of a confidently short picker.\n * The DB's own favourites-first/`updated_at` order is irrelevant: every row\n * is re-sorted client-side by `sortFilteredAgents`.\n */\n\nimport { readAllRows } from \"@ai-matrx/data/db\";\n\nimport type {\n AgentCatalogClient,\n AgentCatalogFavorites,\n PgErrorLike,\n} from \"./ports\";\nimport { toAgentSummary } from \"./rows\";\nimport type { AgentSummary } from \"./types\";\n\n/** Rows per page. Must not exceed the server's `db-max-rows`. */\nconst LIST_PAGE_SIZE = 1000;\n\n/** Server search page size — the frontend's `AGENT_SEARCH_LIMIT`. */\nexport const AGENT_SEARCH_LIMIT = 50;\n\nexport class AgentCatalogReadError extends Error {\n override readonly name = \"AgentCatalogReadError\";\n readonly source: string;\n constructor(source: string, detail: string) {\n super(`${source}: ${detail}`);\n this.source = source;\n }\n}\n\nfunction pgDetail(error: PgErrorLike): string {\n return error.code ? `${error.message} (${error.code})` : error.message;\n}\n\n/**\n * Read the WHOLE agent catalogue. Throws rather than returning a partial\n * list — see the file header.\n */\nexport async function readAgentCatalogRows(\n client: AgentCatalogClient,\n): Promise<AgentSummary[]> {\n const raw = await readAllRows<unknown>(\n ({ from, to }) =>\n Promise.resolve(\n client\n .rpc(\"agx_get_list_full\", {}, { count: \"exact\" })\n .order(\"id\", { ascending: true })\n .range(from, to),\n ).then((res) => ({\n // `data` crosses a HOST-generated-type boundary, so it arrives as\n // `unknown` and is narrowed here rather than asserted anywhere.\n data: Array.isArray(res.data) ? (res.data as unknown[]) : null,\n error: res.error,\n count: res.count ?? null,\n })),\n { label: \"agx_get_list_full\", pageSize: LIST_PAGE_SIZE },\n );\n\n const rows: AgentSummary[] = [];\n let dropped = 0;\n for (const item of raw) {\n const summary = toAgentSummary(item);\n if (summary) rows.push(summary);\n else dropped += 1;\n }\n if (dropped > 0) {\n throw new AgentCatalogReadError(\n \"agx_get_list_full\",\n `${dropped} row(s) came back without an id and were refused. A row that ` +\n \"cannot be identified cannot be selected, so the catalogue is not \" +\n \"trustworthy — check the RPC's return shape.\",\n );\n }\n return rows;\n}\n\nexport interface AgentServerSearchResult {\n /** Matched ids in SERVER RANK ORDER. */\n ids: string[];\n /** Full rows for every hit — merged additively into the registry. */\n rows: AgentSummary[];\n}\n\n/**\n * Tier-2 server search. Purely ADDITIVE: it widens what the local filter\n * admits and never removes a row the local scorer already matched.\n */\nexport async function searchAgentsOnServer(\n client: AgentCatalogClient,\n args: { query: string; deep?: boolean; limit?: number },\n): Promise<AgentServerSearchResult> {\n const q = args.query.trim();\n if (!q) return { ids: [], rows: [] };\n\n const { data, error } = await client.rpc(\"agx_search\", {\n p_query: q,\n p_deep: args.deep ?? false,\n p_limit: args.limit ?? AGENT_SEARCH_LIMIT,\n p_offset: 0,\n });\n if (error) throw new AgentCatalogReadError(\"agx_search\", pgDetail(error));\n\n const rows: AgentSummary[] = [];\n if (Array.isArray(data)) {\n for (const item of data) {\n const summary = toAgentSummary(item);\n if (summary) rows.push(summary);\n }\n }\n return { ids: rows.map((r) => r.id), rows };\n}\n\n/**\n * The single-agent read, used when a mandate's resolved Holder is not in the\n * caller's own catalogue (a platform agent nobody has shared, most often).\n *\n * Two existing doors, in order — never a new RPC:\n * 1. `agx_search` with the id as the query. The scorer awards an exact id\n * match 100000, so the row comes back first, and it is the FULL 19-column\n * row (name AND description AND category AND tags).\n * 2. `agx_resolve_agent_address([id])` — the frontend's own name resolver.\n * Name and type only, so the row renders with an honest name and no\n * description rather than a fabricated one.\n *\n * Returns `null` when neither door can name the agent. The caller SCREAMS;\n * it never invents a label.\n */\nexport async function readSingleAgentRow(\n client: AgentCatalogClient,\n agentId: string,\n): Promise<AgentSummary | null> {\n try {\n const hit = await searchAgentsOnServer(client, {\n query: agentId,\n limit: 5,\n });\n const exact = hit.rows.find((r) => r.id === agentId);\n if (exact) return exact;\n } catch {\n // Fall through to the address resolver — a search failure is not a verdict.\n }\n\n const { data, error } = await client.rpc(\"agx_resolve_agent_address\", {\n p_ids: [agentId],\n });\n if (error) {\n throw new AgentCatalogReadError(\n \"agx_resolve_agent_address\",\n pgDetail(error),\n );\n }\n if (!Array.isArray(data)) return null;\n for (const item of data) {\n if (typeof item !== \"object\" || item === null) continue;\n const record = item as Record<string, unknown>;\n if (record[\"agent_id\"] !== agentId) continue;\n const name = record[\"agent_name\"];\n return toAgentSummary({\n id: agentId,\n name: typeof name === \"string\" ? name : null,\n agent_type: record[\"agent_type\"],\n is_active: true,\n });\n }\n return null;\n}\n\n/** The `user_entity_state` entity token for an agent. */\nexport const AGENT_FAVORITE_ENTITY_TYPE = \"agent\";\n\n/**\n * Overlay the caller's stars onto freshly-read rows — ONE `ues_get_bulk`\n * round trip for the whole set. Every row's `isFavorite` is set from\n * `platform.user_entity_state` (true iff the caller starred it); nothing the\n * list RPC returned is trusted for it.\n *\n * A failed star read never blocks the catalogue: it is reported (the caller\n * passes `onError`, which the store routes to the errorSink) and every row\n * renders UNSET — an honest \"no stars known\", never a stale column value.\n */\nexport async function overlayAgentFavorites(\n favorites: AgentCatalogFavorites,\n rows: AgentSummary[],\n onError: (message: string) => void,\n): Promise<AgentSummary[]> {\n if (rows.length === 0) return rows;\n let starred: Set<string> | null = null;\n try {\n const result = await favorites.getBulk(\n AGENT_FAVORITE_ENTITY_TYPE,\n rows.map((r) => r.id),\n );\n if (result.ok) {\n starred = new Set(\n result.data.items.filter((s) => s.isFavorite).map((s) => s.entityId),\n );\n } else {\n onError(result.error.message);\n }\n } catch (e) {\n onError(e instanceof Error ? e.message : String(e));\n }\n return rows.map((r) => {\n const isFavorite = starred?.has(r.id) ?? false;\n return r.isFavorite === isFavorite ? r : { ...r, isFavorite };\n });\n}\n\n/**\n * THE ONE WRITE: the caller's star on one agent, in\n * `platform.user_entity_state` through the favorites port. Throws an\n * `AgentCatalogReadError` carrying the refusal in words.\n */\nexport async function writeAgentFavorite(\n favorites: AgentCatalogFavorites,\n agentId: string,\n isFavorite: boolean,\n): Promise<void> {\n const result = await favorites.setFavorite(\n AGENT_FAVORITE_ENTITY_TYPE,\n agentId,\n isFavorite,\n );\n if (!result.ok) {\n throw new AgentCatalogReadError(\n \"user_entity_state (ues_set)\",\n result.error.code\n ? `${result.error.message} (${result.error.code})`\n : result.error.message,\n );\n }\n}\n","/**\n * catalog/rows.ts — @ai-matrx/agents/catalog\n *\n * The ONE ingress for a database row. `agx_get_list_full()` and `agx_search()`\n * return the same list columns (search adds two ranking columns), so both come\n * through here and produce the identical `AgentSummary`.\n *\n * UNKNOWN COLUMNS ARE IGNORED, BY DESIGN. Every column is read by NAME, so an\n * additive platform migration (the way `orchestra` arrived) reaches consumers\n * on `latest` without a package release, and an older database simply yields\n * `null` for a column it does not have yet.\n *\n * Typed over `unknown` on purpose: the truth of this boundary is a\n * HOST-generated Supabase type this package cannot see (the `@ai-matrx/data`\n * 0.2.1 lesson). Narrowing happens here, once, loudly — a row that is not an\n * object is REFUSED rather than half-read.\n */\n\nimport {\n asAgentId,\n type AgentCatalogAgentType,\n type AgentSummary,\n type OrchestraBadge,\n} from \"./types\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction bool(value: unknown): boolean {\n return value === true;\n}\n\nfunction boolOrNull(value: unknown): boolean | null {\n return typeof value === \"boolean\" ? value : null;\n}\n\nfunction stringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter((v): v is string => typeof v === \"string\");\n}\n\n/** `agent_type` is a DB-owned enum; anything but `builtin` is a user agent. */\nfunction agentType(value: unknown): AgentCatalogAgentType {\n return value === \"builtin\" ? \"builtin\" : \"user\";\n}\n\n/**\n * The `orchestra` column, or `null` for an ordinary agent.\n *\n * ADDITIVE-TOLERANT BY CONSTRUCTION: this column arrived after 0.7.x, and a\n * client reading a database that predates it (or a mirror that dropped it)\n * simply sees `null` and shows no badge — never a crash, never a half-badge.\n *\n * `depthBudget` is passed through AS DECLARED and never defaulted: the\n * platform's fallback ceiling belongs to the server that enforces it. A value\n * that is not a positive finite number is not a declaration, so it reads as\n * absent rather than as a number nobody wrote.\n */\nfunction orchestraBadge(value: unknown): OrchestraBadge | null {\n if (!isRecord(value)) return null;\n const depth = value[\"depth_budget\"];\n const count = value[\"member_count\"];\n return {\n mode: str(value[\"mode\"]) ?? \"supervisor\",\n tagline: str(value[\"tagline\"]),\n depthBudget:\n typeof depth === \"number\" && Number.isFinite(depth) && depth > 0\n ? depth\n : null,\n memberCount:\n typeof count === \"number\" && Number.isFinite(count) && count >= 0\n ? count\n : 0,\n memberTitles: stringArray(value[\"member_titles\"]),\n };\n}\n\n/**\n * Map one raw list/search row. Returns `null` when the row is not an object\n * or carries no id — the caller reports that to the errorSink and drops it;\n * a row with no identity cannot be selected, so rendering it would be a lie.\n */\nexport function toAgentSummary(raw: unknown): AgentSummary | null {\n if (!isRecord(raw)) return null;\n const id = str(raw[\"id\"]);\n if (!id) return null;\n\n return {\n id: asAgentId(id),\n name: str(raw[\"name\"]),\n description: str(raw[\"description\"]),\n category: str(raw[\"category\"]),\n tags: stringArray(raw[\"tags\"]),\n agentType: agentType(raw[\"agent_type\"]),\n modelId: str(raw[\"model_id\"]),\n isActive: bool(raw[\"is_active\"]),\n isArchived: bool(raw[\"is_archived\"]),\n // Stars are per-person (platform.user_entity_state) and are overlaid by\n // `overlayAgentFavorites` — a list row never carries the caller's star.\n isFavorite: false,\n createdBy: str(raw[\"created_by\"]),\n organizationId: str(raw[\"organization_id\"]),\n taskId: str(raw[\"task_id\"]),\n sourceAgentId: str(raw[\"source_agent_id\"]),\n createdAt: str(raw[\"created_at\"]),\n updatedAt: str(raw[\"updated_at\"]),\n isOwner: boolOrNull(raw[\"is_owner\"]),\n accessLevel: str(raw[\"access_level\"]),\n sharedByEmail: str(raw[\"shared_by_email\"]),\n orchestra: orchestraBadge(raw[\"orchestra\"]),\n };\n}\n","/**\n * catalog/default-row.ts — @ai-matrx/agents/catalog\n *\n * THE DEFAULT ROW, and the drift screamer (design D3).\n *\n * What every client used to do: prepend a placeholder row whose id is\n * `mandate:<key>` and whose name and description are HARDCODED, and let the\n * server resolve the real Holder at run time. That is how matrx-local's row\n * came to be labelled \"Matrx Desktop Agent\" while `local.cloud_chat` actually\n * resolves to General Chat — a label lying on screen, with nothing anywhere\n * that could notice.\n *\n * What happens here instead:\n *\n * - A picker instance passes `defaultMandateKey`. The package resolves the\n * Holder through the aidream door `GET /mandates/{key}/resolution`\n * (verified against `aidream/api/routers/mandate_bindings.py`,\n * `get_mandate_resolution`, mounted at prefix `/mandates`) using the\n * injected `transport`.\n * 🚨 THE PLATFORM RULE D-R1: a client NEVER walks the mandate ladder\n * itself. It asks. That is why a `defaultMandateKey` with no transport is\n * a loud config error and not a DB read.\n * - The row renders the Holder's REAL name and description, read from the\n * catalogue rows already in hand, or through ONE existing single-agent\n * read when the Holder is not in this caller's catalogue.\n * - The last resolution is cached in the `storage` port for first paint.\n * - Whenever the cached row and the LIVE resolution disagree on holder id\n * or holder name, the picker shows a PERSISTENT in-picker banner AND the\n * `notifier` port fires. Never a console line, never only a console line.\n *\n * The row's id stays `mandate:<key>` byte-for-byte, because matrx-extend\n * (`src/lib/mandates.ts`) and matrx-local (`desktop/src/lib/mandates.ts`)\n * already hand that exact ref to their hosts.\n */\n\nimport { readSingleAgentRow } from \"./data\";\nimport type {\n MandateResolutionVerdict,\n ResolvedDefaultRow,\n} from \"./default-row-types\";\nimport type {\n AgentCatalogAsyncStorage,\n AgentCatalogClient,\n AgentCatalogErrorSink,\n AgentCatalogStorage,\n AgentCatalogStorageLike,\n AgentCatalogTransport,\n} from \"./ports\";\nimport { mandateAgentId, type AgentSummary } from \"./types\";\n\nconst CACHE_PREFIX = \"ai-matrx.agents.catalog.default-row:\";\n\nexport class MandateDefaultRowError extends Error {\n override readonly name = \"MandateDefaultRowError\";\n readonly mandateKey: string;\n readonly remedy: string;\n constructor(args: { mandateKey: string; message: string; remedy: string }) {\n super(`${args.message} — ${args.remedy}`);\n this.mandateKey = args.mandateKey;\n this.remedy = args.remedy;\n }\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\n/** Narrow the server's `MandateResolutionResponse` to what a picker needs. */\nexport function parseMandateResolution(\n mandateKey: string,\n raw: unknown,\n): MandateResolutionVerdict {\n if (!isRecord(raw)) {\n throw new MandateDefaultRowError({\n mandateKey,\n message: `mandate \"${mandateKey}\": the resolution endpoint did not return an object`,\n remedy:\n \"check that the transport points at the AI Matrx server and that \" +\n \"GET /mandates/{key}/resolution is reachable\",\n });\n }\n const agentId = raw[\"agent_id\"];\n const definitionAgentId = raw[\"definition_agent_id\"];\n const provenance = raw[\"provenance\"];\n const holderType = raw[\"holder_type\"];\n return {\n mandateKey:\n typeof raw[\"mandate_key\"] === \"string\" ? raw[\"mandate_key\"] : mandateKey,\n holderType: typeof holderType === \"string\" ? holderType : \"agent\",\n agentId: typeof agentId === \"string\" ? agentId : null,\n isVersion: raw[\"is_version\"] === true,\n definitionAgentId:\n typeof definitionAgentId === \"string\" ? definitionAgentId : null,\n provenance: typeof provenance === \"string\" ? provenance : \"system\",\n };\n}\n\nasync function askTheServer(\n transport: AgentCatalogTransport,\n mandateKey: string,\n): Promise<MandateResolutionVerdict> {\n const path = `/mandates/${encodeURIComponent(mandateKey)}/resolution`;\n const response = await transport.fetch(path, {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n if (!response.ok) {\n throw new MandateDefaultRowError({\n mandateKey,\n message: `mandate \"${mandateKey}\": the server refused to resolve it (HTTP ${response.status})`,\n remedy:\n response.status === 404\n ? \"the mandate does not exist — check the key this picker was given\"\n : \"check the caller's session and organization context, then retry\",\n });\n }\n return parseMandateResolution(mandateKey, await response.json());\n}\n\n// ── The first-paint cache ───────────────────────────────────────────────────\n\n/** An in-memory storage, used when the host binds none and there is no DOM. */\nexport function createMemoryStorage(): AgentCatalogStorage {\n const map = new Map<string, string>();\n return {\n getItem: (k) => map.get(k) ?? null,\n setItem: (k, v) => {\n map.set(k, v);\n },\n removeItem: (k) => {\n map.delete(k);\n },\n };\n}\n\n/**\n * DEFAULT storage: `localStorage` when it exists AND answers (a private\n * window, a service worker, or SSR all fail differently), else memory.\n */\nexport function defaultStorage(): AgentCatalogStorage {\n try {\n const ls = (globalThis as { localStorage?: AgentCatalogStorage })\n .localStorage;\n if (ls) {\n const probe = `${CACHE_PREFIX}__probe__`;\n ls.setItem(probe, \"1\");\n ls.removeItem(probe);\n return ls;\n }\n } catch {\n // fall through\n }\n return createMemoryStorage();\n}\n\nexport function readCachedDefaultRow(\n storage: AgentCatalogStorage,\n mandateKey: string,\n): ResolvedDefaultRow | null {\n try {\n const raw = storage.getItem(CACHE_PREFIX + mandateKey);\n if (!raw) return null;\n const parsed: unknown = JSON.parse(raw);\n if (!isRecord(parsed)) return null;\n const holderId = parsed[\"holderId\"];\n const holderName = parsed[\"holderName\"];\n if (typeof holderId !== \"string\" || typeof holderName !== \"string\") {\n return null;\n }\n const description = parsed[\"holderDescription\"];\n const provenance = parsed[\"provenance\"];\n const at = parsed[\"at\"];\n return {\n mandateKey,\n holderId,\n holderName,\n holderDescription: typeof description === \"string\" ? description : null,\n provenance: typeof provenance === \"string\" ? provenance : \"system\",\n at: typeof at === \"number\" ? at : 0,\n };\n } catch {\n return null;\n }\n}\n\nexport function writeCachedDefaultRow(\n storage: AgentCatalogStorage,\n resolved: ResolvedDefaultRow,\n): void {\n try {\n storage.setItem(CACHE_PREFIX + resolved.mandateKey, JSON.stringify(resolved));\n } catch {\n // A full or refusing storage costs a first paint, never correctness.\n }\n}\n\n// ── The async-capable storage seam (0.9.0) ──────────────────────────────────\n//\n// 🚨 THE WEB PATH IS UNCHANGED. Both functions below await whatever the store\n// hands back; a synchronous `localStorage` value is not a promise, so it is\n// already in hand and the behaviour, the cache key and the parse are\n// byte-identical to `readCachedDefaultRow` / `writeCachedDefaultRow` above —\n// which stay exported, and stay synchronous, for every existing caller.\n\n/** Parse whatever the store held under this mandate's key. */\nfunction parseCachedDefaultRow(\n mandateKey: string,\n raw: string | null,\n): ResolvedDefaultRow | null {\n try {\n if (!raw) return null;\n const parsed: unknown = JSON.parse(raw);\n if (!isRecord(parsed)) return null;\n const holderId = parsed[\"holderId\"];\n const holderName = parsed[\"holderName\"];\n if (typeof holderId !== \"string\" || typeof holderName !== \"string\") {\n return null;\n }\n const description = parsed[\"holderDescription\"];\n const provenance = parsed[\"provenance\"];\n const at = parsed[\"at\"];\n return {\n mandateKey,\n holderId,\n holderName,\n holderDescription: typeof description === \"string\" ? description : null,\n provenance: typeof provenance === \"string\" ? provenance : \"system\",\n at: typeof at === \"number\" ? at : 0,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Read the cached row from EITHER storage shape. A store that throws or answers\n * with a rejected promise costs a first paint, never correctness.\n */\nexport async function readCachedDefaultRowAsync(\n storage: AgentCatalogStorageLike,\n mandateKey: string,\n): Promise<ResolvedDefaultRow | null> {\n let raw: string | null;\n try {\n raw = await (storage as AgentCatalogAsyncStorage).getItem(\n CACHE_PREFIX + mandateKey,\n );\n } catch {\n return null;\n }\n return parseCachedDefaultRow(mandateKey, raw);\n}\n\n/** Write the cached row to EITHER storage shape. */\nexport async function writeCachedDefaultRowAsync(\n storage: AgentCatalogStorageLike,\n resolved: ResolvedDefaultRow,\n): Promise<void> {\n try {\n await (storage as AgentCatalogAsyncStorage).setItem(\n CACHE_PREFIX + resolved.mandateKey,\n JSON.stringify(resolved),\n );\n } catch {\n // A full or refusing storage costs a first paint, never correctness.\n }\n}\n\n// ── Building the row ────────────────────────────────────────────────────────\n\n/** Build the `mandate:<key>` row from a resolved Holder. Never hardcodes text. */\nexport function defaultRowFromResolution(\n resolved: ResolvedDefaultRow,\n): AgentSummary {\n return {\n id: mandateAgentId(resolved.mandateKey),\n name: resolved.holderName,\n description: resolved.holderDescription,\n category: null,\n tags: [],\n agentType: \"builtin\",\n modelId: null,\n isActive: true,\n isArchived: false,\n isFavorite: false,\n createdBy: null,\n organizationId: null,\n taskId: null,\n sourceAgentId: resolved.holderId,\n createdAt: null,\n updatedAt: null,\n isOwner: null,\n accessLevel: null,\n sharedByEmail: null,\n // A mandate default row is a live reference to whichever agent the mandate\n // resolves to; the badge belongs to the RESOLVED agent's own catalog row.\n orchestra: null,\n mandateKey: resolved.mandateKey,\n };\n}\n\n/**\n * The drift verdict. Cached vs live: a changed holder id OR a changed holder\n * name is drift. Returns the sentence to show, or `null` when they agree.\n */\nexport function detectDefaultRowDrift(\n cached: ResolvedDefaultRow | null,\n live: ResolvedDefaultRow,\n): string | null {\n if (!cached) return null;\n if (cached.holderId !== live.holderId) {\n return (\n `The default agent for \"${live.mandateKey}\" changed: this screen was ` +\n `showing \"${cached.holderName}\", and the platform now resolves it to ` +\n `\"${live.holderName}\". The list below is correct; anything that cached ` +\n \"the old name is not.\"\n );\n }\n if (cached.holderName !== live.holderName) {\n return (\n `The default agent for \"${live.mandateKey}\" was renamed: \"` +\n `${cached.holderName}\" is now \"${live.holderName}\".`\n );\n }\n return null;\n}\n\nexport interface ResolveDefaultRowArgs {\n mandateKey: string;\n transport: AgentCatalogTransport;\n client: AgentCatalogClient;\n storage: AgentCatalogStorageLike;\n errorSink: AgentCatalogErrorSink;\n /**\n * Look the Holder up in the rows this catalog already holds. May answer\n * asynchronously: the store waits for an in-flight list read before\n * declaring a miss, so a default row never costs a second network read just\n * because the verdict outran the list (the list read now also overlays the\n * caller's stars).\n */\n lookupRow: (\n agentId: string,\n ) => AgentSummary | undefined | Promise<AgentSummary | undefined>;\n}\n\nexport interface ResolveDefaultRowOutcome {\n resolved: ResolvedDefaultRow;\n row: AgentSummary;\n /** Non-null when the cached first-paint row disagreed with the live answer. */\n drift: string | null;\n}\n\n/**\n * Ask the server, name the Holder for real, cache the answer, and report\n * drift. Throws `MandateDefaultRowError` when the mandate cannot produce a\n * runnable agent — a picker never renders a default row it cannot name.\n */\nexport async function resolveDefaultRow(\n args: ResolveDefaultRowArgs,\n): Promise<ResolveDefaultRowOutcome> {\n const { mandateKey, transport, client, storage, lookupRow } = args;\n const cached = await readCachedDefaultRowAsync(storage, mandateKey);\n\n const verdict = await askTheServer(transport, mandateKey);\n\n if (verdict.holderType !== \"agent\") {\n throw new MandateDefaultRowError({\n mandateKey,\n message:\n `mandate \"${mandateKey}\": the ${verdict.provenance} rung names a ` +\n `${verdict.holderType} Holder, and an agent picker can only offer an agent`,\n remedy: `rebind the ${verdict.provenance} rung to an agent, or drop defaultMandateKey from this picker`,\n });\n }\n\n const holderId = verdict.definitionAgentId ?? verdict.agentId;\n if (!holderId) {\n throw new MandateDefaultRowError({\n mandateKey,\n message: `mandate \"${mandateKey}\": the server resolved it without naming an agent`,\n remedy: `bind the ${verdict.provenance} rung to an agent`,\n });\n }\n\n let holder = await lookupRow(holderId);\n if (!holder) {\n holder = (await readSingleAgentRow(client, holderId)) ?? undefined;\n }\n if (!holder || !holder.name) {\n throw new MandateDefaultRowError({\n mandateKey,\n message:\n `mandate \"${mandateKey}\": its Holder resolved, but nothing this ` +\n \"caller can read could name that agent\",\n remedy:\n \"grant this user access to the Holder, or make it a platform agent — \" +\n \"the picker will not print a placeholder name in its place\",\n });\n }\n\n const resolved: ResolvedDefaultRow = {\n mandateKey,\n holderId,\n holderName: holder.name,\n holderDescription: holder.description,\n provenance: verdict.provenance,\n at: Date.now(),\n };\n\n const drift = detectDefaultRowDrift(cached, resolved);\n await writeCachedDefaultRowAsync(storage, resolved);\n\n return { resolved, row: defaultRowFromResolution(resolved), drift };\n}\n","/**\n * catalog/global-state.ts — @ai-matrx/agents/catalog\n *\n * 🚨 MODULE-LEVEL MUTABLE STATE IS BANNED IN THIS PACKAGE. With dual ESM+CJS\n * output and `splitting: false`, each loader graph instantiates its own copy\n * of every module — a module-level variable would silently split the\n * in-flight dedupe (so the \"one RPC for ~20 mounting surfaces\" collapse\n * would become two), the freshness stamp, the catalog registry, and the\n * default-row cache. Everything session-shared therefore lives on\n * `globalThis` under a `Symbol.for` slot, exactly like\n * `@ai-matrx/kit`'s confirm opener. Never \"clean this up\" into module locals.\n */\n\nimport type { ResolvedDefaultRow } from \"./default-row-types\";\n\n/** One session-shared slot for the whole catalog subsystem. */\nconst STATE_SLOT = Symbol.for(\"ai-matrx.agents.catalog\");\n\nexport interface CatalogGlobalState {\n /**\n * Registry of live catalogs by `catalogId`, so a host that imports the\n * package through two loader graphs still gets ONE catalog per id.\n */\n catalogs: Map<string, unknown>;\n /**\n * Shared promise for an in-progress full-list load. Ported from\n * matrx-frontend's `_listFullInFlight`: ~20 surfaces dispatch the load on\n * mount and several co-exist on one page, with their effects running in\n * the same commit — no component-level or status-based guard can see a\n * sibling's request. Sharing the promise collapses them to one\n * `agx_get_list_full` read while every caller still awaits a real result.\n */\n listInFlight: Map<string, Promise<void>>;\n /** Ported from `_chatListFetchedAt` — the TTL guard's stamp. */\n listFetchedAt: Map<string, number>;\n /** Last live default-row resolution per `catalogId::mandateKey`. */\n defaultRows: Map<string, ResolvedDefaultRow>;\n}\n\nexport function getCatalogGlobalState(): CatalogGlobalState {\n const holder = globalThis as Record<symbol, CatalogGlobalState | undefined>;\n let state = holder[STATE_SLOT];\n if (!state) {\n state = {\n catalogs: new Map(),\n listInFlight: new Map(),\n listFetchedAt: new Map(),\n defaultRows: new Map(),\n };\n holder[STATE_SLOT] = state;\n }\n return state;\n}\n\n/** @internal Test-only: forget every session-shared value. */\nexport function _resetCatalogGlobalState(): void {\n const state = getCatalogGlobalState();\n state.catalogs.clear();\n state.listInFlight.clear();\n state.listFetchedAt.clear();\n state.defaultRows.clear();\n}\n","/**\n * catalog/schema.ts — @ai-matrx/agents/catalog\n *\n * THE DEMANDED SCHEMA PROBE (the `@ai-matrx/associations` `assertDemandedSchema`\n * precedent). It proves that the database a host pointed this catalog at can\n * actually answer the functions the picker demands — the three `agx_*` reads\n * and `ues_get_bulk`, the star read (`platform.user_entity_state`).\n *\n * 🚨 IT MUST BE ABLE TO FAIL. A probe whose green result is unconditional\n * proves nothing, so `selfTest: true` also probes a fabricated function name\n * and REQUIRES it to come back missing. `catalog/__tests__/schema.test.ts`\n * runs the whole probe against a client whose `rpc` answers PostgreSQL 42883\n * (`undefined_function`, which PostgREST surfaces as PGRST202) and asserts the\n * loud error.\n */\n\nimport type { AgentCatalogClient } from \"./ports\";\n\n/** A UUID that cannot exist, so a probe never touches a real row. */\nconst BAD_UUID = \"00000000-0000-0000-0000-000000000000\";\n\nconst SELF_TEST_MISSING_RPC = \"agx_this_function_does_not_exist_probe\";\n\n/** The functions the catalog cannot work without, and safe probe arguments. */\nconst DEMANDED_RPCS: Record<string, Record<string, unknown>> = {\n agx_get_list_full: {},\n agx_search: { p_query: \"__probe__\", p_deep: false, p_limit: 1, p_offset: 0 },\n agx_resolve_agent_address: { p_ids: [BAD_UUID] },\n // The caller's stars. Read-only, and an impossible id touches no row.\n ues_get_bulk: { p_entity_type: \"agent\", p_entity_ids: [BAD_UUID] },\n};\n\nexport interface AgentCatalogSchemaReport {\n ok: boolean;\n /** Demanded functions the database cannot answer. */\n missing: string[];\n /** Functions the probe could not reach (transport/unknown failure). */\n unreachable: { fn: string; error: unknown }[];\n /** Functions that answered (success or any non-missing refusal). */\n answered: string[];\n /**\n * Whether `agx_get_list_full` carries the `orchestra` badge column (added to\n * the platform 2026-09-08).\n *\n * NOT a violation when absent — the picker degrades to no conductor marker,\n * which is honest — but it is never SILENT either: a `false` here is the one\n * signal that tells a host \"this database predates the badge\" instead of\n * leaving someone to wonder why their Orchestra looks like a plain agent.\n * `null` means the probe could not tell (the caller can see no agents at\n * all), never \"fine\".\n */\n orchestraColumn: boolean | null;\n}\n\nexport interface AssertAgentCatalogSchemaOptions {\n /**\n * Also probe a fabricated function name and REQUIRE it to come back\n * missing — proves this probe can fail.\n */\n selfTest?: boolean;\n /** Return the report instead of throwing. The self-test failure ALWAYS throws. */\n throwOnViolation?: boolean;\n}\n\n/**\n * PostgREST reports an unknown function as PGRST202; PostgreSQL's own SQLSTATE\n * for it is 42883. Both are accepted so this probe works through PostgREST AND\n * through any client that surfaces the raw SQLSTATE.\n */\nfunction isMissingFunctionError(error: unknown): boolean {\n if (!error || typeof error !== \"object\") return false;\n const code = (error as { code?: unknown }).code;\n return code === \"PGRST202\" || code === \"42883\";\n}\n\n/**\n * Probe every demanded function. Throws an `Error` naming each missing one\n * (unless `throwOnViolation: false`), and ALWAYS throws when the probe itself\n * cannot be trusted (unreachable database, failed self-test).\n */\nexport async function assertAgentCatalogSchema(\n client: AgentCatalogClient,\n options: AssertAgentCatalogSchemaOptions = {},\n): Promise<AgentCatalogSchemaReport> {\n const { selfTest = false, throwOnViolation = true } = options;\n\n const names = Object.keys(DEMANDED_RPCS);\n if (selfTest) names.push(SELF_TEST_MISSING_RPC);\n\n const missing: string[] = [];\n const unreachable: { fn: string; error: unknown }[] = [];\n const answered: string[] = [];\n let orchestraColumn: boolean | null = null;\n\n for (const fn of names) {\n const args = DEMANDED_RPCS[fn] ?? {};\n try {\n const { data, error } = await client.rpc(fn, args);\n if (fn === \"agx_get_list_full\" && error == null) {\n orchestraColumn = readsOrchestraColumn(data);\n }\n if (error == null) answered.push(fn);\n else if (isMissingFunctionError(error)) missing.push(fn);\n else answered.push(fn);\n } catch (e) {\n unreachable.push({ fn, error: e });\n }\n }\n\n if (selfTest) {\n const selfTestMissing = missing.includes(SELF_TEST_MISSING_RPC);\n const idx = missing.indexOf(SELF_TEST_MISSING_RPC);\n if (idx >= 0) missing.splice(idx, 1);\n const answeredIdx = answered.indexOf(SELF_TEST_MISSING_RPC);\n if (answeredIdx >= 0) answered.splice(answeredIdx, 1);\n if (!selfTestMissing) {\n throw new Error(\n \"assertAgentCatalogSchema self-test FAILED: the fabricated function \" +\n `\"${SELF_TEST_MISSING_RPC}\" did not come back as missing. This probe ` +\n \"cannot currently fail, so its green result proves nothing — the \" +\n \"client is swallowing or faking errors.\",\n );\n }\n }\n\n if (unreachable.length > 0) {\n throw new Error(\n \"assertAgentCatalogSchema could not complete: \" +\n `${unreachable.length} probe call(s) failed to reach the database (` +\n `${unreachable.map((u) => u.fn).join(\", \")}). This is NOT a schema ` +\n \"verdict — fix connectivity and re-run.\",\n );\n }\n\n const ok = missing.length === 0;\n const report: AgentCatalogSchemaReport = {\n ok,\n missing,\n unreachable,\n answered,\n orchestraColumn,\n };\n\n if (!ok && throwOnViolation) {\n throw new Error(\n \"DEMANDED SCHEMA VIOLATION: the database this client points at \" +\n `cannot answer ${missing.length} demanded function(s): ` +\n `${missing.join(\", \")}. @ai-matrx/agents/catalog cannot render a ` +\n \"correct picker against it — point the client at Matrx Main, or apply \" +\n \"the agx_* migrations.\",\n );\n }\n\n return report;\n}\n\n/**\n * `true` when the list rows carry the `orchestra` key, `false` when there ARE\n * rows and none does, `null` when there is nothing to judge from. Reads the\n * KEY, not its value: a conductorless account still proves the column exists.\n */\nfunction readsOrchestraColumn(data: unknown): boolean | null {\n if (!Array.isArray(data) || data.length === 0) return null;\n return data.some(\n (row) =>\n typeof row === \"object\" &&\n row !== null &&\n Object.prototype.hasOwnProperty.call(row, \"orchestra\"),\n );\n}\n","/**\n * catalog/orchestra.ts — @ai-matrx/agents/catalog\n *\n * Creator words for an Orchestra badge. A VERBATIM port of the helpers the\n * Workflow Studio's hand-rolled picker carried (`apps/workflow-studio/src/\n * hooks/use-agents.ts` before `c0f958b43`), lifted here so every client says\n * the same sentence about the same ensemble.\n *\n * Pure — no React, no DOM. The row shape is `OrchestraBadge` in `./types`.\n */\n\nimport type { OrchestraBadge } from \"./types\";\n\n/**\n * Creator words for an Orchestra's run mode. \"supervisor\" is already plain\n * English; the structural modes get humanized (never \"sequential/parallel/dag\"\n * at eye level). An unknown future mode falls through as its own word rather\n * than hiding — visible-but-unpolished beats invisible.\n */\nconst ORCHESTRA_MODE_LABEL: Record<string, string> = {\n supervisor: \"supervisor\",\n sequential: \"in order\",\n parallel: \"together\",\n dag: \"custom flow\",\n};\n\nexport function orchestraModeLabel(mode: string): string {\n return ORCHESTRA_MODE_LABEL[mode] ?? mode;\n}\n\n/** Human label for a badge: \"Orchestra · supervisor · 3 members\" (singular-safe). */\nexport function orchestraLabel(badge: OrchestraBadge): string {\n const n = badge.memberCount;\n return `Orchestra · ${orchestraModeLabel(badge.mode)} · ${n} ${\n n === 1 ? \"member\" : \"members\"\n }`;\n}\n\n/**\n * The member-call ceiling in Creator language (\"Team members can call helpers\n * up to 2 levels deep\"), or `null` when the composition declared none. A badge\n * never invents the platform default: the server that runs the ensemble owns\n * that number, and printing a promise nobody made is worse than printing\n * nothing.\n */\nexport function orchestraDepthLine(badge: OrchestraBadge): string | null {\n const n = badge.depthBudget;\n if (typeof n !== \"number\" || n <= 0) return null;\n return `Team members can call helpers up to ${n} ${\n n === 1 ? \"level\" : \"levels\"\n } deep`;\n}\n\n/**\n * One visible line naming who the Orchestra delegates to, collapsing past\n * `limit` into \"+N more\". `null` when no member carries a real role title —\n * \"Member, Member, Member\" is noise that reads like data.\n */\nexport function orchestraDelegatesLine(\n badge: OrchestraBadge,\n limit = 3,\n): string | null {\n const titles = badge.memberTitles;\n if (titles.length === 0) return null;\n const shown = titles.slice(0, limit);\n const extra = titles.length - shown.length;\n return `Delegates to: ${shown.join(\", \")}${\n extra > 0 ? ` +${extra} more` : \"\"\n }`;\n}\n","/**\n * catalog/labels.ts — @ai-matrx/agents/catalog\n *\n * VERBATIM port of matrx-frontend `features/agents/constants/agent-list-labels.ts`.\n * The only seam inverted: the two label constants moved into the `labels` port\n * (`DEFAULT_AGENT_CATALOG_LABELS.publicTab` / `.publicBadge`) so a host can\n * override them; the FUNCTIONS below keep their exact behaviour.\n */\n\nimport type { AgentCatalogLabels } from \"./ports\";\nimport { ARCHIVE_FILTER_OPTIONS, nextArchFilter } from \"./types\";\nimport type { AgentArchFilter, AgentTab } from \"./types\";\n\nexport function agentListEmptyLabel(\n tab: AgentTab,\n labels: AgentCatalogLabels,\n): string {\n switch (tab) {\n case \"system\":\n // 🚨 The tab IS the system tab, and the surfaces that mount this picker\n // call that rung \"System\" (V1 round 3). Saying \"public\" here made the\n // empty state name a different thing from the rung the person had just\n // chosen. The tab's own LABEL is a wider vocabulary question and is left\n // alone — this only stops the empty state contradicting its own case.\n return labels.emptySystem;\n case \"shared\":\n return labels.emptyShared;\n default:\n return labels.emptyDefault;\n }\n}\n\n/** Whether a list picker should default to the public (`system`) tab instead of Mine. */\nexport function shouldDefaultAgentListToPublicTab(args: {\n userId: string | null;\n ownedCount: number;\n agentsLoaded: boolean;\n}): boolean {\n if (!args.userId) return true;\n if (!args.agentsLoaded) return false;\n return args.ownedCount === 0;\n}\n\n// ── THE ARCHIVED-ITEMS LAW — the control's words, and the honest footer ─────\n//\n// `common-docs/policies/archived-items.md`, Arman 2026-09-09:\n//\n// \"everything should have an archive filter, and the default should always\n// hide archived, but seeing archived items should be one or two clicks\n// away.\"\n//\n// Clause 2 of that law is why these live here rather than inside a component:\n// \"Counts, badges, footers and pagination count what the list renders — a\n// screen never lies.\" The footer string is computed ONCE, from the same\n// numbers the list rendered, for both platforms.\n\n/** What the filter-bar chip reads in each state. */\nexport function agentArchiveFilterChipLabel(archFilter: AgentArchFilter): string {\n return (\n ARCHIVE_FILTER_OPTIONS.find((o) => o.value === archFilter)?.chip ?? \"Archive\"\n );\n}\n\n/** The platform's words for the state — menus, aria-labels, help text. */\nexport function agentArchiveFilterStateLabel(\n archFilter: AgentArchFilter,\n): string {\n return (\n ARCHIVE_FILTER_OPTIONS.find((o) => o.value === archFilter)?.label ??\n \"Hide archived\"\n );\n}\n\n/**\n * The accessible name of the ONE control, always naming the state it is IN\n * and the state one click moves it to. A control whose label does not say\n * what it currently does is the \"dead or dishonest\" shape the platform bans.\n */\nexport function agentArchiveFilterControlLabel(\n archFilter: AgentArchFilter,\n): string {\n return `Archive filter: ${agentArchiveFilterStateLabel(\n archFilter,\n ).toLowerCase()}. Click for ${agentArchiveFilterStateLabel(\n nextArchFilter(archFilter),\n ).toLowerCase()}`;\n}\n\n/**\n * THE FOOTER. It counts exactly what the list rendered and, whenever archived\n * rows are involved, says so — hidden ones included.\n *\n * hide archived, nothing archived behind it → \"412 agents\"\n * hide archived, 4 archived behind it → \"412 agents · 4 archived hidden\"\n * show all → \"416 agents · archived shown\"\n * archived only → \"4 archived shown\"\n */\nexport function agentListFooterLabel(args: {\n /** Rows actually rendered. */\n count: number;\n archFilter: AgentArchFilter;\n /**\n * Rows this view WOULD render if the filter were flipped to \"archived only\"\n * — exactly what the default state is keeping off the screen. Only ever\n * read in the `active` state.\n */\n archivedHiddenCount: number;\n}): string {\n const { count, archFilter, archivedHiddenCount } = args;\n if (archFilter === \"archived\") return `${count} archived shown`;\n const base = `${count} agent${count !== 1 ? \"s\" : \"\"}`;\n if (archFilter === \"both\") return `${base} · archived shown`;\n return archivedHiddenCount > 0\n ? `${base} · ${archivedHiddenCount} archived hidden`\n : base;\n}\n","// catalog/score.ts — @ai-matrx/agents/catalog\n//\n// THE canonical agent relevance scorer. One implementation, every surface,\n// every APP. Ported VERBATIM (behaviour byte-for-byte) from matrx-frontend\n// `features/agents/search/score.ts`; only the file header changed.\n//\n// This existed twice with drifted weights — the gallery copy in\n// `features/agents/redux/agent-consumers/selectors.ts` and a chat-side copy in\n// the (deleted 2026-08) legacy agentCache selectors. The chat copy scored an id\n// match at 50 with no exact-id bonus, so searching a chat-side picker by UUID\n// was effectively dead. Everything now delegates here.\n//\n// Pure: no Redux, no store types, no imports. Anything that can describe an\n// agent structurally can be scored.\n//\n// Adding a field? Add it here and it lights up on every surface at once.\n// Never fork this function.\n//\n// ── SQL PARITY (load-bearing) ───────────────────────────────────────────────\n// `public.agx_search_score` in migrations/agx_search_score.sql is the SQL\n// mirror of this function. Server-side paging FORCES a second implementation —\n// relevance has to be computed before LIMIT, which the browser cannot do — but\n// the two must stay in lockstep.\n//\n// CHANGE ONE, CHANGE THE OTHER IN THE SAME COMMIT, and keep the weights below\n// identical to the SQL constants. Guarded by score.parity.test.ts against the\n// shared fixture in __fixtures__/search-score-parity.json.\n//\n// This is not hypothetical: /agents/all shipped with a flat SQL `ILIKE OR` and\n// no ranking at all, so a description match tied with a name match and\n// searching \"image\" buried every image agent under unrelated ones.\n\n/**\n * The structural shape a record needs to be searchable. Every field except\n * `id` is optional so both the full gallery record and the slim chat record\n * satisfy it without adapters.\n */\nexport interface AgentSearchable {\n id: string;\n name?: string | null;\n description?: string | null;\n category?: string | null;\n tags?: string[] | null;\n modelId?: string | null;\n agentType?: string | null;\n outputFormat?: string | null;\n sharedByEmail?: string | null;\n}\n\n/**\n * Relevance score for an agent against a query. Higher = more relevant.\n * Returns 0 when nothing matches (0 is the \"no match\" contract — see\n * `agentMatchesSearch`).\n *\n * Scores only fields carried by the list-level fetches. Message content and\n * variable definitions are deliberately excluded: they are not loaded by the\n * list RPCs, so matching them here would be a false promise. Server-side\n * search owns deep content matching.\n */\nexport function computeAgentSearchScore(\n agent: AgentSearchable,\n query: string,\n): number {\n const q = query.trim().toLowerCase();\n if (!q) return 0;\n\n let score = 0;\n\n const name = (agent.name ?? \"\").toLowerCase();\n const desc = (agent.description ?? \"\").toLowerCase();\n\n if (name === q) score += 10000;\n else if (name.startsWith(q)) score += 5000;\n // Word-boundary beats a mid-word substring: \"image\" ranks\n // \"Basic Image Generator\" above \"Reimagine Helper\".\n else if (matchesWholeWord(name, q)) score += 3000;\n else if (name.includes(q)) score += 2000;\n\n if (desc === q) score += 1000;\n else if (desc.includes(q)) score += 500;\n\n if (agent.category?.toLowerCase().includes(q)) score += 300;\n if (agent.tags?.some((t) => t.toLowerCase().includes(q))) score += 300;\n if (agent.modelId?.toLowerCase().includes(q)) score += 100;\n if (agent.agentType?.toLowerCase().includes(q)) score += 100;\n if (agent.outputFormat?.toLowerCase().includes(q)) score += 100;\n\n // Id search — an exact UUID always wins outright so you can paste an id from\n // a URL or a log line and land on that agent, on any surface.\n const id = agent.id.toLowerCase();\n if (id === q) score += 100000;\n else if (id.includes(q)) score += 5000;\n\n // Helps find agents shared by a specific person.\n if (agent.sharedByEmail?.toLowerCase().includes(q)) score += 200;\n\n // Multi-term fallback: \"image gen\" matches nothing as a phrase. Score per\n // TERM, and only when EVERY term lands somewhere — so multi-word searches\n // work without degrading into a loose OR that matches half the list.\n if (score === 0 && q.includes(\" \")) {\n const terms = q.split(/\\s+/).filter(Boolean);\n let hits = 0;\n let termScore = 0;\n for (const term of terms) {\n const inName = name.includes(term);\n const matched =\n inName ||\n desc.includes(term) ||\n (agent.category?.toLowerCase().includes(term) ?? false) ||\n (agent.tags?.some((t) => t.toLowerCase().includes(term)) ?? false);\n if (matched) {\n hits += 1;\n termScore += inName ? 400 : 100;\n }\n }\n // All-or-nothing: a partial term match is not a match.\n if (hits === terms.length) score += termScore;\n }\n\n return score;\n}\n\n/** True when `q` appears in `haystack` on word boundaries. */\nfunction matchesWholeWord(haystack: string, q: string): boolean {\n const escaped = q.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return new RegExp(`\\\\b${escaped}\\\\b`).test(haystack);\n}\n\n/** True when the agent matches the query at all. */\nexport function agentMatchesSearch(\n agent: AgentSearchable,\n query: string,\n): boolean {\n return computeAgentSearchScore(agent, query) > 0;\n}\n","/**\n * catalog/selectors.ts — @ai-matrx/agents/catalog\n *\n * VERBATIM port of matrx-frontend\n * `features/agents/redux/agent-consumers/selectors.ts`.\n *\n * ALL filter, sort, search-scoring, category/tag extraction and pagination\n * logic lives here — not in components. Two coupling seams inverted, nothing\n * else:\n *\n * 1. `createSelector` (reselect) → `memoize1`/`memoize2`/`memoize3` below,\n * the same last-arguments reference-equality memoization reselect\n * defaults to. No Redux, no store types.\n * 2. `AgentDefinitionRecord` → `AgentSummary`, the list-row shape\n * `agx_get_list_full` actually returns.\n *\n * One structural consequence of (2), recorded rather than hidden: the\n * frontend's `selectLiveAgents` filters `isVersion` snapshots out of a store\n * that also holds them. This catalog only ever holds list rows — a version\n * snapshot cannot enter it — so that filter is a no-op here and is not\n * ported.\n *\n * 🚨 TWO DELIBERATE DEPARTURES FROM THE ORIGINAL, both defects the port\n * inherited and 0.9.1 fixes at the class (see CHANGELOG 0.9.1):\n *\n * F1 — every sort now ends on `id` ASC, the same final key `agx_get_list`\n * ends on, so the order of TIED rows is defined by the rows instead of\n * by whichever transport the host used to fetch them.\n * F5 — the tab-badge counts honour the archive filter, so the badge, the\n * footer and the rendered rows are the same number.\n *\n * Everything else below is byte-identical to the original.\n */\n\nimport {\n agentMatchesSearch,\n computeAgentSearchScore,\n} from \"./score\";\nimport {\n AGENT_NONE_SENTINEL,\n type AgentArchFilter,\n type AgentConsumerState,\n type AgentSortOption,\n type AgentSummary,\n} from \"./types\";\n\nexport { computeAgentSearchScore, agentMatchesSearch };\nexport { AGENT_NONE_SENTINEL };\n\n// ── Constants (verbatim) ─────────────────────────────────────────────────────\n\nexport const AGENT_CARDS_LIMIT_DESKTOP = 8;\nexport const AGENT_CARDS_LIMIT_MOBILE = 4;\nexport const AGENT_LIST_ITEMS_PER_PAGE = 20;\n\n// ── Memoization (the reselect seam, inverted) ───────────────────────────────\n\n/**\n * Last-arguments memoization on reference equality — reselect's default\n * `defaultMemoize` behaviour, in eleven lines and with no dependency. A\n * selector built here is memoized PER INSTANCE, exactly like a\n * `createSelector` result, so the factories below keep their contract:\n * build the selector once per (consumerId, …) and reuse it.\n */\nexport function memoize1<A, R>(fn: (a: A) => R): (a: A) => R {\n let lastA: A | undefined;\n let last: R;\n let has = false;\n return (a: A): R => {\n if (!has || lastA !== a) {\n last = fn(a);\n lastA = a;\n has = true;\n }\n return last;\n };\n}\n\nexport function memoize2<A, B, R>(fn: (a: A, b: B) => R): (a: A, b: B) => R {\n let lastA: A | undefined;\n let lastB: B | undefined;\n let last: R;\n let has = false;\n return (a: A, b: B): R => {\n if (!has || lastA !== a || lastB !== b) {\n last = fn(a, b);\n lastA = a;\n lastB = b;\n has = true;\n }\n return last;\n };\n}\n\nexport function memoize3<A, B, C, R>(\n fn: (a: A, b: B, c: C) => R,\n): (a: A, b: B, c: C) => R {\n let lastA: A | undefined;\n let lastB: B | undefined;\n let lastC: C | undefined;\n let last: R;\n let has = false;\n return (a: A, b: B, c: C): R => {\n if (!has || lastA !== a || lastB !== b || lastC !== c) {\n last = fn(a, b, c);\n lastA = a;\n lastB = b;\n lastC = c;\n has = true;\n }\n return last;\n };\n}\n\n// ── Pure sort comparator ────────────────────────────────────────────────────\n\n/**\n * 🚨 THE FINAL TIEBREAKER. `agx_get_list` orders\n * `is_favorite DESC, updated_at DESC, id` — `id` ASCENDING is the unique key\n * that makes the SERVER's order TOTAL. Every sort in this file ends on the\n * same key, so the rendered order is a function of the ROWS and never of the\n * order they happened to arrive in.\n *\n * Why a raw `<` / `>` and not `localeCompare`: Postgres orders `uuid` by its\n * 16 raw bytes. The canonical text form is lowercase hex with dashes at fixed\n * positions, so a codepoint comparison of those strings reproduces the\n * database's order exactly. A locale collator does not — it is free to fold\n * case or ignore punctuation, and would silently diverge from the server on\n * precisely the ties this key exists to settle.\n */\nexport function compareAgentIds(a: AgentSummary, b: AgentSummary): number {\n const idA = a.id ?? \"\";\n const idB = b.id ?? \"\";\n if (idA < idB) return -1;\n if (idA > idB) return 1;\n return 0;\n}\n\n/**\n * The chosen sort key, then `id`. TOTAL for every option.\n *\n * Before 0.9.1 each branch below returned 0 for tied rows, which left their\n * relative order to whatever `Array.prototype.sort` had been handed — i.e. to\n * the transport. A host that fetched the RPC in one shot kept the server's\n * favourites-first/`updated_at DESC` order for ties; a host that paged it with\n * `order=id.asc` kept id-ASC. Same rows, same filters, two different screens.\n * The key below is the server's own, so both now render the server's answer.\n */\nexport function applyAgentSortComparator(\n a: AgentSummary,\n b: AgentSummary,\n sortBy: AgentSortOption,\n): number {\n const primary = compareAgentSortKey(a, b, sortBy);\n // An unparseable timestamp yields NaN, which `sort` reads as \"equal\" while\n // defeating `!== 0`. Collapse it to a tie so the id key still decides — a\n // total order must not depend on the data being clean.\n if (!Number.isFinite(primary) || primary === 0) return compareAgentIds(a, b);\n return primary;\n}\n\n/** The chosen key ALONE — no tiebreaker. Not total; not for rendering. */\nfunction compareAgentSortKey(\n a: AgentSummary,\n b: AgentSummary,\n sortBy: AgentSortOption,\n): number {\n switch (sortBy) {\n case \"name-asc\":\n return (a.name ?? \"\").localeCompare(b.name ?? \"\");\n case \"name-desc\":\n return (b.name ?? \"\").localeCompare(a.name ?? \"\");\n case \"created-desc\":\n return +new Date(b.createdAt ?? 0) - +new Date(a.createdAt ?? 0);\n case \"category-asc\":\n return (a.category ?? \"\").localeCompare(b.category ?? \"\");\n case \"updated-desc\":\n default:\n return +new Date(b.updatedAt ?? 0) - +new Date(a.updatedAt ?? 0);\n }\n}\n\n// ── Category / tag metadata (derived from live agents) ──────────────────────\n\n/** All unique categories across live USER agents, sorted alphabetically. */\nexport const selectAllAgentCategories = memoize1(\n (agents: readonly AgentSummary[]): string[] => {\n const cats = new Set<string>();\n for (const a of agents) {\n if (a.agentType === \"user\" && a.category) cats.add(a.category);\n }\n return Array.from(cats).sort();\n },\n);\n\n/**\n * All unique categories across live SYSTEM (builtin) agents. The system tab\n * gets the same category filter every other tab has — its options just come\n * from a different population.\n */\nexport const selectAllSystemAgentCategories = memoize1(\n (agents: readonly AgentSummary[]): string[] => {\n const cats = new Set<string>();\n for (const a of agents) {\n if (a.agentType === \"builtin\" && a.category) cats.add(a.category);\n }\n return Array.from(cats).sort();\n },\n);\n\n/** All unique tags across live user agents, sorted alphabetically. */\nexport const selectAllAgentTags = memoize1(\n (agents: readonly AgentSummary[]): string[] => {\n const tags = new Set<string>();\n for (const a of agents) {\n if (a.agentType === \"user\") a.tags?.forEach((t) => tags.add(t));\n }\n return Array.from(tags).sort();\n },\n);\n\n/** All unique tags across live SYSTEM (builtin) agents. */\nexport const selectAllSystemAgentTags = memoize1(\n (agents: readonly AgentSummary[]): string[] => {\n const tags = new Set<string>();\n for (const a of agents) {\n if (a.agentType === \"builtin\") a.tags?.forEach((t) => tags.add(t));\n }\n return Array.from(tags).sort();\n },\n);\n\n// ── User-owned + shared agents (excludes builtins) ─────────────────────────\n\n/** Live user-type agents (excludes builtins). */\nexport const selectUserTypeAgents = memoize1(\n (agents: readonly AgentSummary[]): AgentSummary[] =>\n agents.filter((a) => a.agentType === \"user\"),\n);\n\n/** Builtin/system agents only. For chat pickers and full catalogues. */\nexport const selectBuiltinTypeAgents = memoize1(\n (agents: readonly AgentSummary[]): AgentSummary[] =>\n agents.filter((a) => a.agentType === \"builtin\"),\n);\n\n// ── Pure filter pipelines (verbatim) ───────────────────────────────────────\n\n/**\n * The ONE ordering rule, and it is TOTAL on every path.\n *\n * searching: score DESC → server rank ASC → sort key → id ASC\n * not searching: favourites first (when asked) → sort key → id ASC\n *\n * `id` ASC is the final key `agx_get_list` itself ends on, so two hosts that\n * fetched the same rows through different transports render the same screen.\n */\nexport function sortFilteredAgents(\n filtered: AgentSummary[],\n consumer: AgentConsumerState,\n): AgentSummary[] {\n const { searchTerm, sortBy, favFilter, favoritesFirst } = consumer;\n\n if (searchTerm) {\n const scores = new Map<string, number>();\n filtered.forEach((a) => {\n scores.set(a.id, computeAgentSearchScore(a, searchTerm));\n });\n\n // Server rank, used only to order matches the local scorer cannot see\n // (tier-2 prompt hits). Locally-scored matches all have score > 0, so\n // they sort above this group unconditionally — obvious matches first.\n const serverRank = new Map<string, number>();\n consumer.serverMatchedIds.forEach((id, i) => serverRank.set(id, i));\n\n return [...filtered].sort((a, b) => {\n const sa = scores.get(a.id) ?? 0;\n const sb = scores.get(b.id) ?? 0;\n if (sb !== sa) return sb - sa;\n if (sa === 0) {\n const ra = serverRank.get(a.id);\n const rb = serverRank.get(b.id);\n if (ra !== undefined && rb !== undefined && ra !== rb) return ra - rb;\n }\n return applyAgentSortComparator(a, b, sortBy);\n });\n }\n\n return [...filtered].sort((a, b) => {\n if (favoritesFirst && favFilter === \"all\") {\n const aFav = a.isFavorite ? 1 : 0;\n const bFav = b.isFavorite ? 1 : 0;\n if (bFav !== aFav) return bFav - aFav;\n }\n return applyAgentSortComparator(a, b, sortBy);\n });\n}\n\n/** User-type agents — mine / shared / all tabs with full consumer filters. */\nexport function filterUserTypeAgents(\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n): AgentSummary[] {\n const {\n searchTerm,\n includedCats,\n includedTags,\n favFilter,\n archFilter,\n accessFilter,\n tab,\n } = consumer;\n\n // Built once, not per row — this runs on every keystroke over the full list.\n const serverMatched = new Set(consumer.serverMatchedIds);\n\n const filtered = agents.filter((agent) => {\n if (tab === \"mine\" && agent.isOwner !== true) return false;\n if (\n tab === \"shared\" &&\n !(agent.isOwner === false && agent.accessLevel != null)\n )\n return false;\n\n // THE ARCHIVED-ITEMS LAW, through the ONE predicate every tab, badge and\n // footer in this package shares.\n if (!agentMatchesArchiveFilter(agent, archFilter)) return false;\n\n if (favFilter === \"yes\" && !agent.isFavorite) return false;\n if (favFilter === \"no\" && agent.isFavorite) return false;\n\n if (accessFilter === \"owned\" && agent.isOwner !== true) return false;\n if (accessFilter === \"shared\" && agent.isOwner !== false) return false;\n if (\n accessFilter === \"editable\" &&\n agent.accessLevel !== \"owner\" &&\n agent.accessLevel !== \"admin\" &&\n agent.accessLevel !== \"editor\"\n )\n return false;\n\n if (includedCats.length > 0) {\n const category = agent.category;\n if (!category) {\n if (!includedCats.includes(AGENT_NONE_SENTINEL)) return false;\n } else if (!includedCats.includes(category)) {\n return false;\n }\n }\n\n if (includedTags.length > 0) {\n const isUntagged = !agent.tags?.length;\n if (isUntagged) {\n if (!includedTags.includes(AGENT_NONE_SENTINEL)) return false;\n } else if (!agent.tags?.some((t) => includedTags.includes(t))) {\n return false;\n }\n }\n\n // A server hit counts as a match even when the local scorer scores 0 —\n // that is the only way tier-2 prompt matches can reach the screen, since\n // the client never loads prompt content to score against.\n if (\n searchTerm &&\n !agentMatchesSearch(agent, searchTerm) &&\n !serverMatched.has(agent.id)\n )\n return false;\n\n return true;\n });\n\n return sortFilteredAgents(filtered, consumer);\n}\n\n/**\n * Builtin/system agents (tab === \"system\").\n *\n * Gets the SAME filter surface every other tab has — search, favorites,\n * category, tags, sort, AND THE ARCHIVE FILTER. Only the ownership/access\n * filters are skipped, because a builtin has no owner to filter on. A picker\n * that offers less on one tab than another is the exact half-built shape this\n * list exists to prevent.\n *\n * 🚨 0.9.2 — THE BUILTIN ARCHIVE EXEMPTION IS GONE, AND IT IS NOW ILLEGAL.\n *\n * Until 0.9.1 this function applied no archive filter, on the theory that \"a\n * builtin belongs to the platform and is never the user's to archive\". The\n * database disagreed: `Foundry Planner`\n * (`001b22f6-fa4d-40c6-a1a4-8575d4d04379`) is an ARCHIVED builtin, and it\n * rendered at Public index 216 and was pickable — while Mine / Shared / All\n * hid their archived rows. One picker, two rules, and a person could choose a\n * retired agent from the one tab that did not obey.\n *\n * THE ARCHIVED-ITEMS LAW (`common-docs/policies/archived-items.md`, Arman\n * 2026-09-09) closed the question for every entity at once: \"everything should\n * have an archive filter, and the default should always hide archived… all\n * archived items should always be treated the same.\" Clause 4 makes it a\n * class, not an instance — so there is no per-tab, per-entity or per-surface\n * exemption left to grant, here or anywhere.\n */\nexport function filterBuiltinTypeAgents(\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n): AgentSummary[] {\n const { searchTerm, favFilter, archFilter, includedCats, includedTags } =\n consumer;\n const serverMatched = new Set(consumer.serverMatchedIds);\n\n const filtered = agents.filter((agent) => {\n // THE LAW, first and unconditional — identical to the user-tab rule above.\n if (!agentMatchesArchiveFilter(agent, archFilter)) return false;\n\n if (favFilter === \"yes\" && !agent.isFavorite) return false;\n if (favFilter === \"no\" && agent.isFavorite) return false;\n\n if (includedCats.length > 0) {\n const category = agent.category;\n if (!category) {\n if (!includedCats.includes(AGENT_NONE_SENTINEL)) return false;\n } else if (!includedCats.includes(category)) {\n return false;\n }\n }\n\n if (includedTags.length > 0) {\n const isUntagged = !agent.tags?.length;\n if (isUntagged) {\n if (!includedTags.includes(AGENT_NONE_SENTINEL)) return false;\n } else if (!agent.tags?.some((t) => includedTags.includes(t))) {\n return false;\n }\n }\n\n if (\n searchTerm &&\n !agentMatchesSearch(agent, searchTerm) &&\n !serverMatched.has(agent.id)\n )\n return false;\n\n return true;\n });\n\n return sortFilteredAgents(filtered, consumer);\n}\n\n// ── Filtered agents (user + system tabs) ───────────────────────────────────\n\n/** Factory: owned user-type agents with consumer filters applied (ignores tab). */\nexport const makeSelectFilteredOwnedAgents = () =>\n memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentSummary[] =>\n filterUserTypeAgents(selectUserTypeAgents(agents), {\n ...consumer,\n tab: \"mine\",\n }),\n );\n\n/** Factory: shared user-type agents with consumer filters applied (ignores tab). */\nexport const makeSelectFilteredSharedAgents = () =>\n memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentSummary[] =>\n filterUserTypeAgents(selectUserTypeAgents(agents), {\n ...consumer,\n tab: \"shared\",\n }),\n );\n\n/**\n * Factory: filters and sorts agents for a consumer. User tabs (mine / shared /\n * all) draw from user-type agents; the system tab draws from builtins.\n *\n * `includeSystemInAll` is the ADMIN reading of the \"All\" tab. For a normal\n * user, system agents are a separate catalogue and \"All\" means \"all of MY\n * agents\". For an admin surface, system agents ARE their agents — so \"All\"\n * must be a single blended list, with each row still labelled (the `system`\n * badge on `AgentRow`) so the two are never confused.\n */\nexport const makeSelectFilteredAgents = (includeSystemInAll = false) =>\n memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentSummary[] => {\n const userAgents = selectUserTypeAgents(agents);\n const builtinAgents = selectBuiltinTypeAgents(agents);\n if (consumer.tab === \"system\") {\n return filterBuiltinTypeAgents(builtinAgents, consumer);\n }\n if (includeSystemInAll && consumer.tab === \"all\") {\n return [\n ...filterUserTypeAgents(userAgents, consumer),\n ...filterBuiltinTypeAgents(builtinAgents, consumer),\n ];\n }\n return filterUserTypeAgents(userAgents, consumer);\n },\n );\n\n/** Factory: filters and sorts builtin agents for the chat agent picker. */\nexport const makeSelectFilteredBuiltinAgents = () =>\n memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentSummary[] =>\n filterBuiltinTypeAgents(selectBuiltinTypeAgents(agents), consumer),\n );\n\n// ── Card / list split (verbatim) ───────────────────────────────────────────\n\nexport interface AgentListPage {\n items: AgentSummary[];\n hasMore: boolean;\n totalAfterCards: number;\n}\n\nfunction pageAfterCards(\n filtered: AgentSummary[],\n limit: number,\n page: number,\n): AgentListPage {\n const afterCards = filtered.slice(limit);\n const pageEnd = page * AGENT_LIST_ITEMS_PER_PAGE;\n const items = afterCards.slice(0, pageEnd);\n return {\n items,\n hasMore: items.length < afterCards.length,\n totalAfterCards: afterCards.length,\n };\n}\n\n/** Factory: slices filtered owned agents into the \"cards\" hero section. */\nexport const makeSelectOwnedAgentCards = (isMobile: boolean) => {\n const selectFiltered = makeSelectFilteredOwnedAgents();\n const limit = isMobile ? AGENT_CARDS_LIMIT_MOBILE : AGENT_CARDS_LIMIT_DESKTOP;\n return memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentSummary[] => selectFiltered(agents, consumer).slice(0, limit),\n );\n};\n\n/** Factory: paginated list items for owned agents (everything after cards). */\nexport const makeSelectOwnedAgentListItems = (isMobile: boolean) => {\n const selectFiltered = makeSelectFilteredOwnedAgents();\n const limit = isMobile ? AGENT_CARDS_LIMIT_MOBILE : AGENT_CARDS_LIMIT_DESKTOP;\n return memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentListPage =>\n pageAfterCards(selectFiltered(agents, consumer), limit, consumer.listPage),\n );\n};\n\n/** Factory: slices filtered shared agents into the \"cards\" hero section. */\nexport const makeSelectSharedAgentCards = (isMobile: boolean) => {\n const selectFiltered = makeSelectFilteredSharedAgents();\n const limit = isMobile ? AGENT_CARDS_LIMIT_MOBILE : AGENT_CARDS_LIMIT_DESKTOP;\n return memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentSummary[] => selectFiltered(agents, consumer).slice(0, limit),\n );\n};\n\n/** Factory: paginated list items for shared agents (everything after cards). */\nexport const makeSelectSharedAgentListItems = (isMobile: boolean) => {\n const selectFiltered = makeSelectFilteredSharedAgents();\n const limit = isMobile ? AGENT_CARDS_LIMIT_MOBILE : AGENT_CARDS_LIMIT_DESKTOP;\n return memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentListPage =>\n pageAfterCards(\n selectFiltered(agents, consumer),\n limit,\n consumer.sharedPage,\n ),\n );\n};\n\n// ── Convenience count selectors ────────────────────────────────────────────\n\n/** Factory: total count of filtered agents for a consumer. */\nexport const makeSelectFilteredAgentsCount = () => {\n const selectFiltered = makeSelectFilteredAgents();\n return memoize2(\n (agents: readonly AgentSummary[], consumer: AgentConsumerState): number =>\n selectFiltered(agents, consumer).length,\n );\n};\n\n/** Factory: total count of filtered builtin agents for a consumer. */\nexport const makeSelectFilteredBuiltinAgentsCount = () => {\n const selectFiltered = makeSelectFilteredBuiltinAgents();\n return memoize2(\n (agents: readonly AgentSummary[], consumer: AgentConsumerState): number =>\n selectFiltered(agents, consumer).length,\n );\n};\n\n// ── Consumer state convenience selectors ──────────────────────────────────\n\n/** Returns whether a consumer has any non-default filters active. */\nexport function agentConsumerHasActiveFilters(\n consumer: AgentConsumerState,\n defaults: AgentConsumerState,\n): boolean {\n return (\n consumer.tab !== defaults.tab ||\n consumer.sortBy !== defaults.sortBy ||\n consumer.searchTerm !== \"\" ||\n consumer.includedCats.length > 0 ||\n consumer.includedTags.length > 0 ||\n consumer.favFilter !== defaults.favFilter ||\n consumer.archFilter !== defaults.archFilter ||\n consumer.accessFilter !== defaults.accessFilter ||\n consumer.favoritesFirst !== defaults.favoritesFirst\n );\n}\n\n// ── Aggregate counts (for tab badges) ─────────────────────────────────────\n\n/**\n * 🚨 A BADGE COUNTS WHAT THE TAB RENDERS. Nothing else.\n *\n * Before 0.9.1 these five counted every user-type row, archived included,\n * while `filterUserTypeAgents` (archive filter `active`, the default) hid the\n * archived ones. The badge said \"Mine 416\", the list showed 412 rows and the\n * footer said \"412 agents\" — one screen, three numbers, one of them a lie\n * about agents the user cannot see or reach from there.\n *\n * `is_archived` is now honoured by the same rule the list uses, so the badge,\n * the footer and the rows agree on every tab and under every archive filter.\n *\n * 🚨 0.9.2 — AND THERE IS NO LONGER AN EXCEPTION. The system tab used to be\n * one (\"a builtin is never the user's to archive\"), which was false in the\n * database and illegal under THE ARCHIVED-ITEMS LAW. Its badge now counts\n * under the same archive rule its rows render under, so `Foundry Planner`\n * leaves the Public badge and the Public list together, or returns to both\n * together — never one without the other.\n */\nexport function agentMatchesArchiveFilter(\n agent: AgentSummary,\n archFilter: AgentArchFilter,\n): boolean {\n if (archFilter === \"active\") return !agent.isArchived;\n if (archFilter === \"archived\") return Boolean(agent.isArchived);\n return true;\n}\n\n/** Builtin rows matching an archive filter — the Public tab's badge. */\nfunction countBuiltinRows(\n agents: readonly AgentSummary[],\n archFilter: AgentArchFilter,\n): number {\n let n = 0;\n for (const a of agents) {\n if (a.agentType !== \"builtin\") continue;\n if (!agentMatchesArchiveFilter(a, archFilter)) continue;\n n += 1;\n }\n return n;\n}\n\nfunction countUserRows(\n agents: readonly AgentSummary[],\n archFilter: AgentArchFilter,\n predicate: (a: AgentSummary) => boolean,\n): number {\n let n = 0;\n for (const a of agents) {\n if (a.agentType !== \"user\") continue;\n if (!agentMatchesArchiveFilter(a, archFilter)) continue;\n if (predicate(a)) n += 1;\n }\n return n;\n}\n\nconst isOwned = (a: AgentSummary) => a.isOwner === true;\nconst isShared = (a: AgentSummary) =>\n a.isOwner === false && a.accessLevel != null;\nconst isAny = () => true;\nconst isFavorite = (a: AgentSummary) => Boolean(a.isFavorite);\n\n/**\n * The four tab badges for a consumer's CURRENT archive filter — the numbers\n * `useAgentListCore` puts on the tab strip. Flip the archive filter to\n * \"archived\" and the badges follow the list into the archive.\n */\nexport const selectAgentTabCounts = memoize2(\n (\n agents: readonly AgentSummary[],\n archFilter: AgentArchFilter,\n ): { mine: number; shared: number; all: number; system: number } => ({\n mine: countUserRows(agents, archFilter, isOwned),\n shared: countUserRows(agents, archFilter, isShared),\n all: countUserRows(agents, archFilter, isAny),\n system: countBuiltinRows(agents, archFilter),\n }),\n);\n\n/** Live user-type agents the default (`active`) list renders. */\nexport const selectTotalUserAgentsCount = memoize1(\n (agents: readonly AgentSummary[]): number =>\n countUserRows(agents, \"active\", isAny),\n);\n\nexport const selectTotalOwnedAgentsCount = memoize1(\n (agents: readonly AgentSummary[]): number =>\n countUserRows(agents, \"active\", isOwned),\n);\n\nexport const selectTotalSharedAgentsCount = memoize1(\n (agents: readonly AgentSummary[]): number =>\n countUserRows(agents, \"active\", isShared),\n);\n\n/**\n * Live builtin agents the DEFAULT (`active`) list renders — archived builtins\n * excluded, exactly like every other \"total\" beside it. Before 0.9.2 this\n * counted archived builtins too, which is how an archived `Foundry Planner`\n * reached the Public badge.\n */\nexport const selectTotalBuiltinAgentsCount = memoize1(\n (agents: readonly AgentSummary[]): number => countBuiltinRows(agents, \"active\"),\n);\n\nexport const selectTotalFavoriteAgentsCount = memoize1(\n (agents: readonly AgentSummary[]): number =>\n countUserRows(agents, \"active\", isFavorite),\n);\n"],"mappings":"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","names":["isFavorite","isRecord","isFavorite"]}
1
+ {"version":3,"sources":["../../catalog/types.ts","../../catalog/ports.ts","../../catalog/store.ts","../../catalog/data.ts","../../catalog/rows.ts","../../catalog/default-row.ts","../../catalog/global-state.ts","../../catalog/schema.ts","../../catalog/orchestra.ts","../../catalog/labels.ts","../../catalog/score.ts","../../catalog/selectors.ts"],"sourcesContent":["/**\n * `@ai-matrx/agents/catalog` — the row shape and the per-consumer view state.\n *\n * `AgentSummary` is the 19-column row `agx_get_list_full()` returns, camelCased.\n * It is deliberately NOT the editable agent record: dirty tracking, undo,\n * messages, tools and `_fetchStatus` stay in whichever host owns the editor.\n * A list row is a list row.\n *\n * The view-state types are a VERBATIM port of matrx-frontend\n * `features/agents/redux/agent-consumers/slice.ts` — only the coupling seam\n * inverts (Redux reducers become store actions in `./store`).\n */\n\n/**\n * A branded agent id. Every id that reaches `onSelect` is one of these:\n * either a `agent.definition` UUID, or the `mandate:<key>` reference a\n * default row carries (byte-identical to the ref shape matrx-extend\n * `src/lib/mandates.ts` and matrx-local `desktop/src/lib/mandates.ts`\n * already hand back to their hosts).\n *\n * 🚨 The brand is a STRING LITERAL, never `unique symbol`. This package emits\n * `./catalog` and `./catalog/react` as two separate bundles, so each `.d.ts`\n * carries its own copy of these declarations. A `unique symbol` brand is\n * NOMINAL: two copies of it are unrelated types, so `createAgentCatalog()`\n * from `./catalog` was not assignable to `<AgentCatalogProvider catalog=…>`\n * from `./catalog/react` — the exact two-import wiring the README, the\n * CHANGELOG and every consumer use. A literal brand is structural, so the two\n * copies unify, while a bare `string` still cannot be passed where an\n * `AgentId` is required (which is the whole point of branding). Any future\n * brand in this package follows the same rule.\n */\nexport type AgentId = string & { readonly __agentId: \"ai-matrx.agent-id\" };\n\n/** Brand a raw string as an `AgentId`. */\nexport function asAgentId(value: string): AgentId {\n return value as AgentId;\n}\n\n/** The `mandate:<key>` ref shape every client already speaks. */\nexport function mandateAgentId(mandateKey: string): AgentId {\n return `mandate:${mandateKey}` as AgentId;\n}\n\n/** True when an id is a mandate default row rather than a stored agent. */\nexport function isMandateAgentId(id: string): boolean {\n return id.startsWith(\"mandate:\");\n}\n\n/** `agent_type` verbatim. Only `builtin` changes how a row is grouped. */\nexport type AgentCatalogAgentType = \"user\" | \"builtin\";\n\n/**\n * `access_level` verbatim from `agx_get_list_full`. Widened over the raw\n * string because it is a DB-owned vocabulary: an unknown level renders as\n * itself rather than being coerced into a wrong one.\n */\nexport type AgentAccessLevel =\n | \"owner\"\n | \"admin\"\n | \"editor\"\n | \"viewer\"\n | \"system\"\n | (string & {});\n\n/**\n * Present on a catalog row ONLY when that agent is an **Orchestra** — a\n * conductor that delegates to member agents at run time. Choosing one for a\n * step, a chat or a workflow node runs the whole ensemble, so a person has to\n * be able to SEE that before choosing, not discover it from the run.\n *\n * The DB decides. `agx_get_list_full` / `agx_get_list` / `agx_search` build\n * this from `platform.associations` (the conductor self-edge plus its member\n * edges) in one `agx_orchestra_badges()` join — never a second fetch, and\n * never a per-row read. `null` for every ordinary agent.\n *\n * History: the badge lived only in the Python `GET /agents` route, so every\n * client lost it when the pickers moved to the RPC. It is a ROW FIELD now, in\n * the one read every client shares.\n */\nexport interface OrchestraBadge {\n /** How the ensemble runs: `supervisor` | `sequential` | `parallel` | `dag`, or a future mode verbatim. */\n mode: string;\n /** The composition's one-line description, when its author wrote one. */\n tagline: string | null;\n /**\n * The per-composition delegation-depth budget AS DECLARED, or `null` when\n * the composition declares none. Deliberately NOT defaulted here: the\n * platform's fallback ceiling is enforced by the server that runs the\n * ensemble, and a badge that invented a number would be reporting a promise\n * nobody made.\n */\n depthBudget: number | null;\n /** Member edges. From the ROW count, so an unlabelled ensemble still counts. */\n memberCount: number;\n /** Only REAL role titles — an ensemble with unlabelled edges yields `[]`. */\n memberTitles: string[];\n}\n\n/**\n * One `agx_get_list_full()` row, camelCased. Nineteen columns, no more:\n * anything richer needs a different read and is a different type.\n */\nexport interface AgentSummary {\n id: AgentId;\n name: string | null;\n description: string | null;\n category: string | null;\n tags: string[];\n agentType: AgentCatalogAgentType;\n modelId: string | null;\n /**\n * The agent's CLASS pin (`settings.offering_id` — which serving class of\n * the model runs, e.g. \"Matrx Lightning\"). `null` = no pin (the model's\n * preferred class runs). ABSENT = the read did not carry the column, so the\n * class is unknown and a display must name the model alone.\n */\n offeringId?: string | null;\n isActive: boolean;\n isArchived: boolean;\n isFavorite: boolean;\n createdBy: string | null;\n organizationId: string | null;\n taskId: string | null;\n sourceAgentId: string | null;\n createdAt: string | null;\n updatedAt: string | null;\n // Access metadata\n isOwner: boolean | null;\n accessLevel: AgentAccessLevel | null;\n sharedByEmail: string | null;\n /**\n * The Orchestra badge, or `null` for an ordinary agent. Strict: every row\n * carries the key, so a surface reads `agent.orchestra` and never has to ask\n * whether the column existed.\n */\n orchestra: OrchestraBadge | null;\n /**\n * Set only on a mandate default row — the key it resolved through, so a\n * host can tell \"the default\" from a stored agent without parsing the id.\n */\n mandateKey?: string;\n}\n\n// ── Per-consumer view state (verbatim port of the agent-consumers slice) ─────\n\nexport type AgentSortOption =\n | \"updated-desc\"\n | \"created-desc\"\n | \"name-asc\"\n | \"name-desc\"\n | \"category-asc\";\n\n/**\n * The sort choices a picker offers, in order. PURE DATA, so it lives in the\n * pure entry: a server-reachable manifest reads it at module scope, and\n * importing it from the client-stamped `./catalog/react` bundle dragged React\n * into a server graph for the sake of five string pairs. `./catalog/react`\n * re-exports it unchanged, so no consumer has to move.\n *\n * (Written \"client-stamped\", never with the literal directive: this comment is\n * emitted into `dist/catalog/index.d.ts`, and the tarball canary rightly\n * refuses that directive anywhere in a PURE entry.)\n */\nexport const SORT_OPTIONS: { value: AgentSortOption; label: string }[] = [\n { value: \"updated-desc\", label: \"Recent\" },\n { value: \"created-desc\", label: \"Created\" },\n { value: \"name-asc\", label: \"A → Z\" },\n { value: \"name-desc\", label: \"Z → A\" },\n { value: \"category-asc\", label: \"Category\" },\n];\n\n/** Which ownership tab is active in the agent list. */\nexport type AgentTab = \"mine\" | \"shared\" | \"all\" | \"system\";\n\n/** Favorite filter. */\nexport type AgentFavFilter = \"all\" | \"yes\" | \"no\";\n\n/**\n * The archive filter — THE ARCHIVED-ITEMS LAW's ONE control, in this\n * package's existing vocabulary.\n *\n * > \"everything should have an archive filter, and the default should always\n * > hide archived, but seeing archived items should be one or two clicks\n * > away.\" — Arman, 2026-09-09 (`common-docs/policies/archived-items.md`)\n *\n * Three states and no more, identical for every entity on the platform:\n *\n * | value | the platform's words | what the list shows |\n * |------------|----------------------|--------------------------|\n * | `active` | hide archived | only un-archived rows |\n * | `both` | show all | every row |\n * | `archived` | archived only | only archived rows |\n *\n * `active` is the platform default, and it is a KNOB — see\n * `AgentCatalogConfig.defaults.archiveFilter`.\n */\nexport type AgentArchFilter = \"active\" | \"archived\" | \"both\";\n\n/** Every legal archive-filter value, in the order the control cycles them. */\nexport const ARCHIVE_FILTER_ORDER: readonly AgentArchFilter[] = [\n \"active\",\n \"both\",\n \"archived\",\n];\n\nexport interface AgentArchFilterOption {\n value: AgentArchFilter;\n /** The platform's own words for the state — what a menu row would read. */\n label: string;\n /** What the filter-bar chip reads while this state is the active one. */\n chip: string;\n}\n\n/**\n * 🚨 ONE CONTROL, THREE STATES, SAME WORDS EVERYWHERE. A surface that invents\n * its own archive vocabulary breaks clause 3 of the law (\"the same primitive\n * everywhere … not a per-feature invention\").\n */\nexport const ARCHIVE_FILTER_OPTIONS: readonly AgentArchFilterOption[] = [\n { value: \"active\", label: \"Hide archived\", chip: \"Archive\" },\n { value: \"both\", label: \"Show all\", chip: \"All + archived\" },\n { value: \"archived\", label: \"Archived only\", chip: \"Archived only\" },\n];\n\n/**\n * The next state of the cycling control: hide archived → show all → archived\n * only → hide archived. Pure, so the web chip and the native chip cannot\n * drift apart, and so \"the control reveals archived rows in ONE action\" is a\n * testable claim rather than a UI opinion.\n */\nexport function nextArchFilter(current: AgentArchFilter): AgentArchFilter {\n const index = ARCHIVE_FILTER_ORDER.indexOf(current);\n if (index < 0) return ARCHIVE_FILTER_ORDER[0] as AgentArchFilter;\n return ARCHIVE_FILTER_ORDER[\n (index + 1) % ARCHIVE_FILTER_ORDER.length\n ] as AgentArchFilter;\n}\n\n/** True when `value` is one of the three legal states. */\nexport function isAgentArchFilter(value: unknown): value is AgentArchFilter {\n return value === \"active\" || value === \"archived\" || value === \"both\";\n}\n\n/**\n * Access level filter.\n * 'any' = no restriction (default).\n * 'owned' = only agents the user owns (isOwner = true).\n * 'shared' = only agents shared with the user (isOwner = false).\n * 'editable' = owner + admin + editor.\n */\nexport type AgentAccessFilter = \"any\" | \"owned\" | \"shared\" | \"editable\";\n\n/** Sentinel meaning \"include uncategorized / untagged\" items. */\nexport const AGENT_NONE_SENTINEL = \"__none__\";\n\nexport interface AgentConsumerState {\n tab: AgentTab;\n sortBy: AgentSortOption;\n searchTerm: string;\n\n /** INCLUSION model: empty = show all; non-empty = only matching. */\n includedCats: string[];\n\n /** INCLUSION model: empty = show all; non-empty = only matching. */\n includedTags: string[];\n\n favFilter: AgentFavFilter;\n archFilter: AgentArchFilter;\n accessFilter: AgentAccessFilter;\n favoritesFirst: boolean;\n\n /** Current page for owned-agent list items (after the card section). */\n listPage: number;\n\n /** Current page for shared-agent list items. */\n sharedPage: number;\n\n /**\n * Ids returned by the last server-side search (`agx_search`), in server rank\n * order. Additive: an agent in this list survives the search filter even\n * when the local scorer gives it 0.\n *\n * That is load-bearing for tier 2. A deep search matches an agent's prompt\n * content, which the client never loads — so the local scorer cannot see it.\n * Without this list the server would return prompt matches and the UI would\n * immediately filter them back out.\n *\n * Server-only matches sort BELOW every locally-scored match, in server rank\n * order, so obvious matches always come first.\n */\n serverMatchedIds: string[];\n\n /** True while a server search is in flight — drives the search spinner. */\n isServerSearching: boolean;\n\n /** Tier 2: also search agent prompt content. Opt-in, per consumer. */\n deepSearch: boolean;\n}\n\nexport const DEFAULT_AGENT_CONSUMER_STATE: AgentConsumerState = {\n tab: \"mine\",\n sortBy: \"updated-desc\",\n searchTerm: \"\",\n includedCats: [],\n includedTags: [],\n favFilter: \"all\",\n archFilter: \"active\",\n accessFilter: \"any\",\n favoritesFirst: true,\n listPage: 1,\n sharedPage: 1,\n serverMatchedIds: [],\n isServerSearching: false,\n deepSearch: false,\n};\n\n/** The subset of consumer state a caller may patch (paging is derived). */\nexport type AgentConsumerPatch = Partial<\n Omit<AgentConsumerState, \"listPage\" | \"sharedPage\">\n>;\n\n// ── Loud configuration failure ───────────────────────────────────────────────\n\n/**\n * Thrown by `createAgentCatalog` when a REQUIRED port is missing or an\n * optional feature was asked for without the port it needs. Never a warning,\n * never a degraded catalog: a picker that cannot read is not a picker.\n */\nexport class AgentCatalogConfigError extends Error {\n override readonly name = \"AgentCatalogConfigError\";\n /** Machine code, for a host that routes config failures. */\n readonly code: string;\n /** What the host must do, in a sentence a person can act on. */\n readonly remedy: string;\n\n constructor(args: { code: string; message: string; remedy: string }) {\n super(`${args.message} — ${args.remedy}`);\n this.code = args.code;\n this.remedy = args.remedy;\n }\n}\n","/**\n * `@ai-matrx/agents/catalog` — THE PORTS.\n *\n * Two are required (`client`, `identity`); every other one ships a working\n * default with a DOCUMENTED degradation, per THE ALL-INCLUSIVE LAW. A host\n * injects identity and a Supabase client and nothing else; the picker's only\n * contract back to the host is `onSelect(agentId)`.\n *\n * React appears nowhere in this file — it is import-inert and legal in any\n * graph, server components included.\n */\n\nimport type { AgentArchFilter, AgentSummary } from \"./types\";\n\n// ── The data seam ────────────────────────────────────────────────────────────\n\n/** A PostgREST error, structurally. */\nexport interface PgErrorLike {\n message: string;\n code?: string;\n details?: string | null;\n hint?: string | null;\n}\n\n/** What every supabase-js call resolves to, structurally. */\nexport interface PgResultLike {\n data: unknown;\n error: PgErrorLike | null;\n count?: number | null;\n}\n\n/**\n * The thenable builder supabase-js returns from `.rpc()`. `range` is what\n * makes a COMPLETE list read possible (`readAllRows`); `order` is what makes\n * that paging stable. Both are the real builder's own methods — this is a\n * structural subset, never a re-implementation.\n */\nexport interface AgentCatalogRpcCall extends PromiseLike<PgResultLike> {\n range(from: number, to: number): PromiseLike<PgResultLike>;\n order(column: string, options?: { ascending?: boolean }): AgentCatalogRpcCall;\n}\n\n/**\n * REQUIRED. A structural subset of `SupabaseClient` — anything that can answer\n * `agx_get_list_full`, `agx_search` and `agx_resolve_agent_address`. A real\n * supabase-js client satisfies it as-is. (It is also the data source the\n * DEFAULT favorites port is built on — see `AgentCatalogFavorites`.)\n *\n * Absent → `createAgentCatalog` throws `AgentCatalogConfigError`. There is no\n * degraded mode: the package IS the catalogue read.\n */\nexport interface AgentCatalogClient {\n rpc(\n fn: string,\n args?: Record<string, unknown>,\n options?: { count?: \"exact\" | \"planned\" | \"estimated\" },\n ): AgentCatalogRpcCall;\n}\n\n/**\n * A star is PER-PERSON state and lives in `platform.user_entity_state` — never\n * a column on `agent.definition` (the retired `is_favorite` flag sat on the\n * OWNER's row, so a shared agent could not be starred and two surfaces drifted).\n *\n * This is the structural subset of `@ai-matrx/associations/core`'s\n * `FavoritesServiceApi` the catalog uses — the platform's ONE `ues_*`\n * chokepoint. Results never throw; a refusal comes back as `{ ok: false }`.\n *\n * OPTIONAL. DEFAULT: `createAssociationsStore({ dataSource: client, identity,\n * errorSink }).favorites` — the same chokepoint, built on the same client. A\n * host that already holds a favorites service (matrx-frontend's\n * `favoritesService`) passes it so there is exactly one instance.\n */\nexport interface AgentCatalogFavorites {\n getBulk(\n entityType: string,\n entityIds: string[],\n ): Promise<\n | { ok: true; data: { items: { entityId: string; isFavorite: boolean }[] } }\n | { ok: false; error: { message: string; code?: string } }\n >;\n setFavorite(\n entityType: string,\n entityId: string,\n isFavorite: boolean,\n ): Promise<\n | { ok: true; data: unknown }\n | { ok: false; error: { message: string; code?: string } }\n >;\n}\n\n/**\n * REQUIRED. Who is asking. Needed for the \"zero owned agents → open on the\n * public tab\" heuristic and for the favorites port.\n *\n * `requireUserId` THROWS when there is no session — never a silent anonymous\n * read. The catalog catches that throw in exactly ONE place (the tab-default\n * heuristic, where a signed-out visitor legitimately lands on the public\n * catalogue) and reports it to the `errorSink` the first time; every other\n * caller lets it propagate.\n */\nexport interface AgentCatalogIdentity {\n requireUserId(): string;\n /**\n * OPTIONAL non-throwing twin: the signed-in user id, or `null` for a\n * signed-out visitor. When bound, `null` is a legitimate STATE (a guest\n * page), not a failure — nothing is reported. Bind it whenever the host can\n * tell \"no session\" apart from \"identity is broken\".\n */\n getUserId?(): string | null;\n}\n\n// ── Optional ports, each with a documented degradation ───────────────────────\n\n/**\n * Every degraded path, every failed read, every drift detection reports here.\n * DEFAULT: a tagged `console.error` that announces ONCE that no sink is bound\n * and names the remedy.\n */\nexport type AgentCatalogErrorSink = (event: {\n code: string;\n message: string;\n context?: object;\n}) => void;\n\n/**\n * The drift scream's second channel. DEFAULT: none — and that is safe\n * ONLY because the in-picker persistent banner is the primary scream and\n * always renders. A drift is never console-only.\n */\nexport type AgentCatalogNotifier = (event: {\n level: \"warning\" | \"error\";\n title: string;\n message: string;\n}) => void;\n\n/**\n * First-paint cache for resolved default rows. DEFAULT: `localStorage` when\n * present, else an in-memory map (so SSR and a Chrome service worker both\n * work). Absent storage degrades to \"no first paint of the default row until\n * the mandate resolves\" — never a wrong name on screen.\n */\nexport interface AgentCatalogStorage {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\n/**\n * The SAME seam for a platform whose only key-value store is asynchronous.\n *\n * 🚨 WHY THIS EXISTS (0.9.0). React Native has no `localStorage`; every Expo\n * app's store (`@react-native-async-storage/async-storage`, `expo-secure-store`,\n * MMKV's async face) answers with a promise. Before this, a native host had\n * exactly two options — hand the package a storage that lies by returning\n * `null` synchronously, or lose the default row's first paint entirely. Both\n * are the silent degradation this package exists to refuse.\n *\n * The shape is `AsyncStorage`'s own, so an Expo host passes AsyncStorage\n * directly with no adapter. Every method may answer synchronously OR with a\n * promise, which is what makes `AgentCatalogStorage` a subtype of this one:\n * the WEB PATH IS UNCHANGED — a sync storage still resolves in the same\n * microtask, and `readCachedDefaultRow`/`writeCachedDefaultRow` keep their\n * synchronous signatures for every existing caller.\n */\nexport interface AgentCatalogAsyncStorage {\n getItem(key: string): string | null | Promise<string | null>;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\n/** Either storage shape. What `AgentCatalogConfig.storage` accepts. */\nexport type AgentCatalogStorageLike =\n | AgentCatalogStorage\n | AgentCatalogAsyncStorage;\n\n/** Every user-visible string the picker renders, overridable per host. */\nexport interface AgentCatalogLabels {\n /** User-facing label for the `system` ownership tab. */\n publicTab: string;\n /**\n * Badge label on a builtin row. Default `\"system\"` — the string\n * `AgentRow` actually rendered in matrx-frontend. (The frontend also\n * declared `AGENT_PUBLIC_BADGE_LABEL = \"Public\"` for this badge and NOTHING\n * ever read it — a constant that named the badge without being the badge.\n * Recorded in the CHANGELOG and dropped rather than ported.)\n */\n systemBadge: string;\n /**\n * Badge on an archived row. Archived agents stay offered (THE ARCHIVED-ITEMS\n * LAW: one or two clicks away) and say so on the row itself. Default\n * `\"Archived\"`.\n */\n archivedBadge: string;\n searchPlaceholder: string;\n currentAgentHeading: string;\n emptyDefault: string;\n emptyShared: string;\n emptySystem: string;\n /** Empty state for a signed-out visitor — there is no catalogue to read. */\n emptySignedOut: string;\n loading: string;\n triggerFallback: string;\n triggerResolving: string;\n triggerUnnameable: string;\n hoverHint: string;\n}\n\nexport const DEFAULT_AGENT_CATALOG_LABELS: AgentCatalogLabels = {\n publicTab: \"Public\",\n systemBadge: \"system\",\n archivedBadge: \"Archived\",\n searchPlaceholder: \"Search agents...\",\n currentAgentHeading: \"Current agent\",\n emptyDefault: \"No agents found\",\n emptyShared: \"No shared agents found\",\n emptySystem: \"No system agents found\",\n emptySignedOut: \"Sign in to see your agents\",\n loading: \"Loading...\",\n triggerFallback: \"Agents\",\n triggerResolving: \"Naming the agent…\",\n triggerUnnameable: \"An agent this list cannot name\",\n hoverHint: \"Hover an agent to preview its details, or click to select.\",\n};\n\n// ── The core config ──────────────────────────────────────────────────────────\n\nexport interface AgentCatalogConfig {\n /** REQUIRED — the Supabase client. */\n client: AgentCatalogClient;\n /** REQUIRED — who is asking. */\n identity: AgentCatalogIdentity;\n /** OPTIONAL — see `AgentCatalogFavorites`. */\n favorites?: AgentCatalogFavorites;\n /**\n * The catalog's registry key on `globalThis`. Two `createAgentCatalog`\n * calls with the same id are the same catalog (and the second one screams\n * through the errorSink before replacing the first). Default `\"default\"`.\n */\n catalogId?: string;\n /** OPTIONAL — see `AgentCatalogErrorSink`. */\n errorSink?: AgentCatalogErrorSink;\n /** OPTIONAL — see `AgentCatalogNotifier`. */\n notifier?: AgentCatalogNotifier;\n /**\n * OPTIONAL — see `AgentCatalogStorage` and `AgentCatalogAsyncStorage`. A\n * synchronous store (the web `localStorage` default) and an asynchronous\n * one (React Native's `AsyncStorage`) are both accepted verbatim.\n */\n storage?: AgentCatalogStorageLike;\n /**\n * OPTIONAL — the package's own `MatrxTransport` (`createMatrxTransport`\n * from `@ai-matrx/agents/matrx`). REQUIRED the moment any picker instance\n * passes a `defaultMandateKey`: THE PLATFORM RULE D-R1 says clients never\n * walk the mandate ladder, so the default row can only be resolved through\n * the aidream door `GET /mandates/{mandate_key}/resolution`. A\n * `defaultMandateKey` with no transport throws `AgentCatalogConfigError`.\n */\n transport?: AgentCatalogTransport;\n /** OPTIONAL — label overrides. */\n labels?: Partial<AgentCatalogLabels>;\n /**\n * OPTIONAL — the host's starting values for per-consumer view state.\n * See `AgentCatalogDefaults`.\n */\n defaults?: AgentCatalogDefaults;\n}\n\n/**\n * 🚨 OPINIONS BECOME KNOBS (root law 6). The archive filter's initial state is\n * a configurable default, not code taste — clause 6 of THE ARCHIVED-ITEMS LAW\n * (`common-docs/policies/archived-items.md`) says so explicitly.\n *\n * The PLATFORM default is `\"active\"` (hide archived) and a host that passes\n * nothing gets exactly that. A host wires this to whatever its org/user\n * setting resolves to; an individual picker can still override it per\n * consumer (`useAgentListCore({ initialArchFilter })`), and the person can\n * always change it from the control on the filter bar.\n *\n * An illegal value is NOT coerced to the default — it throws\n * `AgentCatalogConfigError`, because a silently-ignored setting is a knob that\n * lies about being a knob.\n */\nexport interface AgentCatalogDefaults {\n archiveFilter?: AgentArchFilter;\n}\n\n/**\n * The transport seam, structurally identical to `MatrxTransport` from\n * `@ai-matrx/agents/matrx` (declared structurally so `./catalog` never\n * imports the transport module and stays import-inert).\n */\nexport interface AgentCatalogTransport {\n fetch(\n path: string,\n init: {\n method: \"GET\" | \"POST\";\n headers: Record<string, string>;\n body?: string;\n signal?: AbortSignal;\n },\n ): Promise<Response>;\n}\n\n// ── React-layer ports (bound on the provider, never on the headless core) ────\n\n/**\n * Where a row's href goes when someone cmd-clicks it, and where `navigateTo`\n * lands. DEFAULT: `window.location.assign` (so cmd-click and ordinary\n * navigation both work with no host wiring at all).\n */\nexport type AgentCatalogNavigate = (href: string) => void;\n\n/** Resolve a per-row href. DEFAULT: `/agents/go/<id>` — the always-valid door. */\nexport type AgentCatalogResolveHref = (agent: AgentSummary) => string;\n\n/**\n * The sneak-peek affordance. Absent → the affordance is HIDDEN, never a dead\n * button (nothing fails silently, and nothing looks alive when it is not).\n */\nexport type AgentCatalogOpenPeek = (agent: AgentSummary) => void;\n","/**\n * catalog/store.ts — @ai-matrx/agents/catalog\n *\n * `createAgentCatalog(config)` — the headless kernel. Everything the picker\n * knows lives here: the row registry, the complete-list read with its\n * session-shared in-flight dedupe and freshness window, the tier-2 server\n * search, the per-consumer view state, the ONE write, and the mandate default\n * row with its drift screamer.\n *\n * The host injects a Supabase client and who the user is. Nothing else.\n *\n * The consumer reducers below are a VERBATIM port of matrx-frontend\n * `features/agents/redux/agent-consumers/slice.ts`; only the seam inverts\n * (a Redux reducer becomes a store method, and Immer's draft mutation becomes\n * an explicit copy so the store can publish a new reference).\n */\n\nimport { createAssociationsStore } from \"@ai-matrx/associations/core\";\n\nimport {\n overlayAgentFavorites,\n readAgentCatalogRows,\n searchAgentsOnServer,\n writeAgentFavorite,\n} from \"./data\";\nimport type { DefaultRowState } from \"./default-row-types\";\nimport {\n defaultStorage,\n MandateDefaultRowError,\n resolveDefaultRow,\n} from \"./default-row\";\nimport { getCatalogGlobalState } from \"./global-state\";\nimport {\n DEFAULT_AGENT_CATALOG_LABELS,\n type AgentCatalogConfig,\n type AgentCatalogErrorSink,\n type AgentCatalogFavorites,\n type AgentCatalogLabels,\n type AgentCatalogNotifier,\n type AgentCatalogStorageLike,\n} from \"./ports\";\nimport {\n assertAgentCatalogSchema,\n type AgentCatalogSchemaReport,\n type AssertAgentCatalogSchemaOptions,\n} from \"./schema\";\nimport {\n AgentCatalogConfigError,\n DEFAULT_AGENT_CONSUMER_STATE,\n isAgentArchFilter,\n type AgentConsumerPatch,\n type AgentConsumerState,\n type AgentSummary,\n} from \"./types\";\n\n/**\n * Module-level TTL guard, ported from matrx-frontend's `_chatListFetchedAt`.\n * Deliberately NOT view state: it is a session-local guard, not something a\n * person sees. It lives on `globalThis` — see `global-state.ts`.\n */\nconst LIST_TTL_MS = 15 * 60 * 1000; // 15 minutes\nconst LIST_STALE_MS = 4 * 60 * 60 * 1000; // 4 hours — tab-restore threshold\n\nexport type AgentCatalogStatus = \"idle\" | \"loading\" | \"succeeded\" | \"failed\";\n\nexport interface AgentCatalogState {\n /** Every row, one stable array reference per change (memoization depends on it). */\n rows: AgentSummary[];\n byId: Record<string, AgentSummary>;\n status: AgentCatalogStatus;\n error: string | null;\n consumers: Record<string, AgentConsumerState>;\n /** Keyed by mandate key. */\n defaultRows: Record<string, DefaultRowState>;\n}\n\nexport interface AgentCatalog {\n readonly catalogId: string;\n readonly labels: AgentCatalogLabels;\n readonly errorSink: AgentCatalogErrorSink;\n readonly notifier: AgentCatalogNotifier | undefined;\n /** True when this catalog was given a transport and can resolve mandates. */\n readonly canResolveMandates: boolean;\n /**\n * The consumer state a brand-new consumer starts from, AFTER the host's\n * `defaults` knob is applied. Read it instead of\n * `DEFAULT_AGENT_CONSUMER_STATE` whenever the question is \"is this filter at\n * its default?\" — a host that legitimately defaults the archive filter to\n * \"show all\" must not have every control render as though it were modified.\n */\n readonly consumerDefaults: AgentConsumerState;\n\n getState(): AgentCatalogState;\n subscribe(listener: () => void): () => void;\n\n getAgent(agentId: string): AgentSummary | undefined;\n /**\n * The signed-in user id, or `null` when there is no session. The ONE place\n * `identity.requireUserId()`'s throw is caught — a signed-out visitor\n * legitimately lands on the public catalogue — and it is reported to the\n * errorSink the first time so it is never silent.\n */\n getUserIdOrNull(): string | null;\n\n /** Load the catalogue if it is not fresh. Safe to call on every mount. */\n ensureLoaded(options?: { force?: boolean }): Promise<void>;\n /** True when the last load is inside the 15-minute TTL. */\n isFresh(): boolean;\n /** True when the last load is older than 4 hours (tab-restore threshold). */\n isStale(): boolean;\n\n getConsumer(consumerId: string): AgentConsumerState;\n registerConsumer(consumerId: string, initial?: AgentConsumerPatch): void;\n unregisterConsumer(consumerId: string): void;\n setConsumerFilter(consumerId: string, patch: AgentConsumerPatch): void;\n setConsumerPage(\n consumerId: string,\n which: \"list\" | \"shared\",\n page: number,\n ): void;\n setConsumerServerSearch(\n consumerId: string,\n args: { matchedIds?: string[]; isSearching?: boolean },\n ): void;\n resetConsumerFilters(consumerId: string): void;\n\n /** Tier-2 search. Purely additive; merges rows into the registry. */\n searchServer(query: string, deep?: boolean): Promise<string[]>;\n\n /** THE ONE WRITE. Optimistic, rolled back on failure, loud either way. */\n setFavorite(agentId: string, isFavorite: boolean): Promise<void>;\n\n /** Resolve (once) the default row for a mandate key. Idempotent. */\n ensureDefaultRow(mandateKey: string): void;\n getDefaultRow(mandateKey: string): DefaultRowState | undefined;\n /** A person acknowledged the drift banner. The notifier already fired. */\n dismissDefaultRowDrift(mandateKey: string): void;\n /** Re-ask the mandate door for a row that refused (see ensureDefaultRow). */\n retryDefaultRow(mandateKey: string): void;\n\n assertSchema(\n options?: AssertAgentCatalogSchemaOptions,\n ): Promise<AgentCatalogSchemaReport>;\n}\n\n/** DEFAULT error sink: a tagged console.error that names the remedy once. */\nfunction createDefaultErrorSink(): AgentCatalogErrorSink {\n let announced = false;\n return (event) => {\n if (!announced) {\n announced = true;\n // eslint-disable-next-line no-console\n console.error(\n \"[@ai-matrx/agents/catalog] no errorSink is bound, so failures are \" +\n \"only reaching the console. Pass `errorSink` to createAgentCatalog \" +\n \"to route them into your diagnostics surface.\",\n );\n }\n // eslint-disable-next-line no-console\n console.error(`[@ai-matrx/agents/catalog] ${event.code}: ${event.message}`, {\n ...(event.context ?? {}),\n });\n };\n}\n\nfunction errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\nexport function createAgentCatalog(config: AgentCatalogConfig): AgentCatalog {\n if (!config || typeof config !== \"object\") {\n throw new AgentCatalogConfigError({\n code: \"missing_config\",\n message: \"createAgentCatalog was called without a config object\",\n remedy: \"pass { client, identity }\",\n });\n }\n if (!config.client || typeof config.client.rpc !== \"function\") {\n throw new AgentCatalogConfigError({\n code: \"missing_client\",\n message:\n \"createAgentCatalog needs a Supabase client — it IS the catalogue read\",\n remedy:\n \"pass `client` (a supabase-js client, or anything with rpc() and schema().from())\",\n });\n }\n if (!config.identity || typeof config.identity.requireUserId !== \"function\") {\n throw new AgentCatalogConfigError({\n code: \"missing_identity\",\n message: \"createAgentCatalog needs to know who is asking\",\n remedy: \"pass `identity: { requireUserId() }` — never a silent anonymous read\",\n });\n }\n\n const archiveDefault = config.defaults?.archiveFilter;\n if (archiveDefault !== undefined && !isAgentArchFilter(archiveDefault)) {\n // A knob that silently ignores its value is worse than no knob: the host\n // believes the setting took effect and the screen disagrees.\n throw new AgentCatalogConfigError({\n code: \"invalid_archive_default\",\n message:\n `defaults.archiveFilter was ${JSON.stringify(archiveDefault)}, which ` +\n \"is not one of the three states of the platform archive filter\",\n remedy:\n 'pass \"active\" (hide archived), \"both\" (show all) or \"archived\" (archived only)',\n });\n }\n\n /**\n * 🚨 THE ARCHIVED-ITEMS LAW's knob, resolved ONCE. Everything below that\n * needs a starting consumer state reads this, never\n * `DEFAULT_AGENT_CONSUMER_STATE` — so the platform default (\"hide archived\")\n * and a host's override travel the same single path into every consumer,\n * every reset and every \"is this at its default?\" comparison.\n */\n const consumerDefaults: AgentConsumerState = {\n ...DEFAULT_AGENT_CONSUMER_STATE,\n ...(archiveDefault ? { archFilter: archiveDefault } : {}),\n };\n\n const catalogId = config.catalogId ?? \"default\";\n const client = config.client;\n const identity = config.identity;\n const errorSink = config.errorSink ?? createDefaultErrorSink();\n const notifier = config.notifier;\n const storage: AgentCatalogStorageLike = config.storage ?? defaultStorage();\n const transport = config.transport;\n /**\n * Stars live in `platform.user_entity_state`, reached only through the\n * platform's ONE `ues_*` chokepoint. A host that already holds it passes it;\n * otherwise the same chokepoint is built here on the same client.\n */\n const favorites: AgentCatalogFavorites =\n config.favorites ??\n createAssociationsStore({\n // The catalog's client IS a supabase-js client; the associations\n // data-source port is the same `rpc(fn, args)` shape, typed over its\n // own demanded-RPC names.\n dataSource: client as unknown as Parameters<\n typeof createAssociationsStore\n >[0][\"dataSource\"],\n identity,\n errorSink,\n }).favorites;\n function reportFavoriteReadFailure(message: string): void {\n errorSink({\n code: \"favorite_read_failed\",\n message:\n `your starred agents could not be read (${message}); every star is ` +\n \"shown unset until the next catalogue load\",\n context: { catalogId },\n });\n }\n const labels: AgentCatalogLabels = {\n ...DEFAULT_AGENT_CATALOG_LABELS,\n ...(config.labels ?? {}),\n };\n\n const globalState = getCatalogGlobalState();\n if (globalState.catalogs.has(catalogId)) {\n errorSink({\n code: \"catalog_replaced\",\n message:\n `a second agent catalog was created under id \"${catalogId}\" and has ` +\n \"REPLACED the first. Two catalogs with one id share a freshness stamp \" +\n \"and an in-flight promise; give each one its own `catalogId`.\",\n });\n }\n\n let state: AgentCatalogState = {\n rows: [],\n byId: {},\n status: \"idle\",\n error: null,\n consumers: {},\n defaultRows: {},\n };\n\n const listeners = new Set<() => void>();\n function publish(next: AgentCatalogState): void {\n state = next;\n for (const listener of listeners) listener();\n }\n\n // ── The row registry ──────────────────────────────────────────────────────\n\n /** Additive merge — a search hit never removes a row already on screen. */\n function mergeRows(incoming: AgentSummary[]): void {\n if (incoming.length === 0) return;\n const byId = { ...state.byId };\n for (const row of incoming) byId[row.id] = row;\n publish({ ...state, byId, rows: Object.values(byId) });\n }\n\n function replaceRows(incoming: AgentSummary[]): void {\n const byId: Record<string, AgentSummary> = {};\n for (const row of incoming) byId[row.id] = row;\n publish({ ...state, byId, rows: Object.values(byId) });\n }\n\n // ── Identity ──────────────────────────────────────────────────────────────\n\n let anonymousReported = false;\n function getUserIdOrNull(): string | null {\n // A host that can say \"no session\" without throwing has told us a\n // signed-out visitor is a STATE, not a broken identity — never reported.\n if (typeof identity.getUserId === \"function\") return identity.getUserId();\n try {\n return identity.requireUserId();\n } catch (e) {\n if (!anonymousReported) {\n anonymousReported = true;\n errorSink({\n code: \"identity_unavailable\",\n message:\n \"identity.requireUserId() threw, so the picker is treating this \" +\n \"session as signed out and opening on the public catalogue. \" +\n \"Favoriting is unavailable until a session exists.\",\n context: { detail: errorMessage(e) },\n });\n }\n return null;\n }\n }\n\n // ── The complete-list read ───────────────────────────────────────────────\n\n function isFresh(): boolean {\n const at = globalState.listFetchedAt.get(catalogId);\n if (at === undefined) return false;\n return Date.now() - at < LIST_TTL_MS;\n }\n\n function isStale(): boolean {\n const at = globalState.listFetchedAt.get(catalogId);\n if (at === undefined) return true;\n return Date.now() - at > LIST_STALE_MS;\n }\n\n async function load(): Promise<void> {\n // A signed-out visitor HAS no catalogue: `agx_get_list_full` is not\n // executable by `anon`, so the read could only come back 42501 and land\n // as a captured error on every guest page that mounts a picker (live\n // 2026-10-01). Answer the empty catalogue instead, and do NOT stamp\n // freshness — the first `ensureLoaded` after sign-in reads for real.\n if (getUserIdOrNull() === null) {\n if (state.rows.length > 0) replaceRows([]);\n publish({ ...state, status: \"succeeded\", error: null });\n return;\n }\n publish({ ...state, status: \"loading\", error: null });\n try {\n const rows = await overlayAgentFavorites(\n favorites,\n await readAgentCatalogRows(client),\n reportFavoriteReadFailure,\n );\n replaceRows(rows);\n publish({ ...state, status: \"succeeded\", error: null });\n globalState.listFetchedAt.set(catalogId, Date.now());\n } catch (e) {\n const message = errorMessage(e);\n publish({ ...state, status: \"failed\", error: message });\n errorSink({\n code: \"list_read_failed\",\n message: `the agent catalogue could not be read: ${message}`,\n context: { catalogId },\n });\n throw e;\n }\n }\n\n async function ensureLoaded(options?: { force?: boolean }): Promise<void> {\n const force = options?.force ?? false;\n if (!force && isFresh()) return;\n\n // In-flight dedupe (ported verbatim in intent from `_listFullInFlight`):\n // ~20 surfaces call this on mount and several co-exist on one page, with\n // their effects running in the same commit — no component-level or\n // status-based guard can see a sibling's request. Sharing the promise\n // collapses them to ONE read while every caller still awaits a real result.\n const existing = globalState.listInFlight.get(catalogId);\n if (existing) return existing;\n\n const run = load().finally(() => {\n if (globalState.listInFlight.get(catalogId) === run) {\n globalState.listInFlight.delete(catalogId);\n }\n });\n globalState.listInFlight.set(catalogId, run);\n // A rejected shared promise must not become an unhandled rejection for\n // the siblings that merely awaited it — every caller sees the throw.\n return run;\n }\n\n // ── Per-consumer view state (verbatim reducer bodies) ────────────────────\n\n function getConsumer(consumerId: string): AgentConsumerState {\n return state.consumers[consumerId] ?? consumerDefaults;\n }\n\n function writeConsumer(consumerId: string, next: AgentConsumerState): void {\n publish({\n ...state,\n consumers: { ...state.consumers, [consumerId]: next },\n });\n }\n\n function registerConsumer(\n consumerId: string,\n initial?: AgentConsumerPatch,\n ): void {\n // Idempotent — safe on every mount; never resets an existing consumer.\n if (state.consumers[consumerId]) return;\n writeConsumer(consumerId, {\n ...consumerDefaults,\n ...(initial ?? {}),\n });\n }\n\n function unregisterConsumer(consumerId: string): void {\n if (!state.consumers[consumerId]) return;\n const consumers = { ...state.consumers };\n delete consumers[consumerId];\n publish({ ...state, consumers });\n }\n\n function setConsumerFilter(\n consumerId: string,\n patch: AgentConsumerPatch,\n ): void {\n const current = state.consumers[consumerId] ?? { ...consumerDefaults };\n // Paging always resets so nobody is stranded on a page with no results.\n writeConsumer(consumerId, {\n ...current,\n ...patch,\n listPage: 1,\n sharedPage: 1,\n });\n }\n\n function setConsumerPage(\n consumerId: string,\n which: \"list\" | \"shared\",\n page: number,\n ): void {\n const current = state.consumers[consumerId];\n if (!current) return;\n writeConsumer(\n consumerId,\n which === \"list\"\n ? { ...current, listPage: page }\n : { ...current, sharedPage: page },\n );\n }\n\n function setConsumerServerSearch(\n consumerId: string,\n args: { matchedIds?: string[]; isSearching?: boolean },\n ): void {\n const current = state.consumers[consumerId] ?? { ...consumerDefaults };\n // Deliberately does NOT reset pagination: server results arrive after the\n // user already typed, and yanking them to page 1 mid-scroll is its own bug.\n const next: AgentConsumerState = { ...current };\n if (args.matchedIds !== undefined) next.serverMatchedIds = args.matchedIds;\n if (args.isSearching !== undefined) next.isServerSearching = args.isSearching;\n if (\n next.serverMatchedIds === current.serverMatchedIds &&\n next.isServerSearching === current.isServerSearching\n ) {\n return;\n }\n writeConsumer(consumerId, next);\n }\n\n function resetConsumerFilters(consumerId: string): void {\n if (!state.consumers[consumerId]) return;\n writeConsumer(consumerId, { ...consumerDefaults });\n }\n\n // ── Tier-2 server search ─────────────────────────────────────────────────\n\n async function searchServer(query: string, deep = false): Promise<string[]> {\n const result = await searchAgentsOnServer(client, { query, deep });\n mergeRows(\n await overlayAgentFavorites(\n favorites,\n result.rows,\n reportFavoriteReadFailure,\n ),\n );\n return result.ids;\n }\n\n // ── THE ONE WRITE ────────────────────────────────────────────────────────\n\n async function setFavorite(\n agentId: string,\n isFavorite: boolean,\n ): Promise<void> {\n const existing = state.byId[agentId];\n if (!existing) {\n errorSink({\n code: \"favorite_unknown_agent\",\n message: `cannot favorite ${agentId}: it is not in this catalogue`,\n });\n return;\n }\n // Optimistic.\n mergeRows([{ ...existing, isFavorite }]);\n try {\n await writeAgentFavorite(favorites, agentId, isFavorite);\n } catch (e) {\n // Rollback, then SCREAM. A star that silently springs back is a lie.\n mergeRows([existing]);\n errorSink({\n code: \"favorite_write_failed\",\n message: `the favorite could not be saved: ${errorMessage(e)}`,\n context: { agentId, isFavorite },\n });\n notifier?.({\n level: \"error\",\n title: \"Favorite not saved\",\n message:\n \"The star was put back because the change could not be saved. \" +\n \"Check your connection and try again.\",\n });\n throw e;\n }\n }\n\n // ── The mandate default row ──────────────────────────────────────────────\n\n function writeDefaultRow(mandateKey: string, next: DefaultRowState): void {\n publish({\n ...state,\n defaultRows: { ...state.defaultRows, [mandateKey]: next },\n });\n }\n\n const defaultRowsInFlight = new Set<string>();\n\n function ensureDefaultRow(mandateKey: string): void {\n if (!mandateKey) return;\n if (defaultRowsInFlight.has(mandateKey)) return;\n // 🚨 A REFUSAL IS A STATE TO LEAVE, NOT A PLACE TO LIVE. Until 0.13.0 an\n // errored row was cached exactly like a resolved one, so ONE transient\n // refusal (matrx-extend, 2026-09-19: the door was asked a beat before the\n // bearer was readable and answered 401) pinned \"the server refused to\n // resolve it\" on the picker for the rest of the session. A resolved row is\n // still asked once; an errored row is re-asked whenever a surface asks\n // again, because the caller's session, organization or network may have\n // changed since the refusal.\n const current = state.defaultRows[mandateKey];\n if (current && !current.error) return;\n if (!transport) {\n // Loud, typed, and at the moment it is asked for — never a blank row.\n throw new AgentCatalogConfigError({\n code: \"missing_transport\",\n message:\n `a picker asked for the default row of mandate \"${mandateKey}\", but ` +\n \"this catalog has no transport\",\n remedy:\n \"pass `transport` (createMatrxTransport from @ai-matrx/agents/matrx) \" +\n \"to createAgentCatalog — clients never walk the mandate ladder \" +\n \"themselves, they ask the server\",\n });\n }\n defaultRowsInFlight.add(mandateKey);\n writeDefaultRow(mandateKey, {\n mandateKey,\n row: null,\n resolved: null,\n loading: true,\n drift: null,\n error: null,\n });\n\n void (async () => {\n try {\n const outcome = await resolveDefaultRow({\n mandateKey,\n transport,\n client,\n storage,\n errorSink,\n lookupRow: async (id) => {\n const hit = state.byId[id];\n if (hit) return hit;\n const inFlight = globalState.listInFlight.get(catalogId);\n if (!inFlight) return undefined;\n // A failed list read already screamed through its own path;\n // here it only means \"not in the catalogue\".\n await inFlight.catch(() => undefined);\n return state.byId[id];\n },\n });\n getCatalogGlobalState().defaultRows.set(\n `${catalogId}::${mandateKey}`,\n outcome.resolved,\n );\n writeDefaultRow(mandateKey, {\n mandateKey,\n row: outcome.row,\n resolved: outcome.resolved,\n loading: false,\n drift: outcome.drift,\n error: null,\n });\n if (outcome.drift) {\n // 🚨 THE DRIFT SCREAM — the banner above is the primary channel and\n // always renders; the notifier and the sink are additional, never a\n // substitute, and this is never console-only.\n errorSink({\n code: \"default_row_drift\",\n message: outcome.drift,\n context: { mandateKey, holderId: outcome.resolved.holderId },\n });\n notifier?.({\n level: \"warning\",\n title: \"The default agent changed\",\n message: outcome.drift,\n });\n }\n } catch (e) {\n const message =\n e instanceof MandateDefaultRowError ? e.message : errorMessage(e);\n writeDefaultRow(mandateKey, {\n mandateKey,\n row: null,\n resolved: null,\n loading: false,\n drift: null,\n error: message,\n });\n errorSink({\n code: \"default_row_unresolved\",\n message,\n context: { mandateKey },\n });\n } finally {\n defaultRowsInFlight.delete(mandateKey);\n }\n })();\n }\n\n function getDefaultRow(mandateKey: string): DefaultRowState | undefined {\n return state.defaultRows[mandateKey];\n }\n\n function dismissDefaultRowDrift(mandateKey: string): void {\n const current = state.defaultRows[mandateKey];\n if (!current || !current.drift) return;\n writeDefaultRow(mandateKey, { ...current, drift: null });\n }\n\n /**\n * Ask the mandate door again for a row that refused. The errored row is\n * dropped first so the picker shows the in-flight state instead of the old\n * refusal, and an in-flight ask is never doubled.\n */\n function retryDefaultRow(mandateKey: string): void {\n if (!mandateKey || defaultRowsInFlight.has(mandateKey)) return;\n const { [mandateKey]: _dropped, ...rest } = state.defaultRows;\n publish({ ...state, defaultRows: rest });\n ensureDefaultRow(mandateKey);\n }\n\n const catalog: AgentCatalog = {\n catalogId,\n labels,\n errorSink,\n notifier,\n canResolveMandates: transport !== undefined,\n consumerDefaults,\n getState: () => state,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n getAgent: (agentId) => state.byId[agentId],\n getUserIdOrNull,\n ensureLoaded,\n isFresh,\n isStale,\n getConsumer,\n registerConsumer,\n unregisterConsumer,\n setConsumerFilter,\n setConsumerPage,\n setConsumerServerSearch,\n resetConsumerFilters,\n searchServer,\n setFavorite,\n ensureDefaultRow,\n getDefaultRow,\n dismissDefaultRowDrift,\n retryDefaultRow,\n assertSchema: (options) => assertAgentCatalogSchema(client, options),\n };\n\n globalState.catalogs.set(catalogId, catalog);\n return catalog;\n}\n\n/**\n * The catalog registered under `catalogId`, across loader graphs. Returns\n * `undefined` when none has been created yet — never a silent stub.\n */\nexport function getRegisteredAgentCatalog(\n catalogId = \"default\",\n): AgentCatalog | undefined {\n const found = getCatalogGlobalState().catalogs.get(catalogId);\n return found as AgentCatalog | undefined;\n}\n","/**\n * catalog/data.ts — @ai-matrx/agents/catalog\n *\n * Every database call the catalog makes, and nothing else. Five of them:\n *\n * 1. `agx_get_list_full()` — the complete catalogue (owned + directly-shared\n * + org-shared user agents, unioned with active builtins).\n * 2. `agx_search(p_query, p_deep, p_limit, p_offset)` — tier-2 server search.\n * 3. `agx_resolve_agent_address(p_ids)` — the single-agent name read, used\n * when a mandate's Holder is not in the caller's own catalogue.\n * 4. The caller's stars: `ues_get_bulk('agent', ids)` through the\n * favorites port (`platform.user_entity_state`), overlaid on every row\n * set this module returns to the store.\n * 5. ONE write: the caller's star, `ues_set` through the same port. The\n * retired `agent.definition.is_favorite` column is never read or written.\n *\n * 🚨 THE LIST READ IS COMPLETE OR IT THROWS. PostgREST caps every response at\n * `db-max-rows` (1000 on Matrx Main) and reports success — matrx-frontend's\n * `fetchAgentsListFull` issued a bare `.rpc()` and would silently have\n * returned 1000 rows of a larger catalogue (the ~400-builtin truncation\n * incident is the near-miss). Here the read goes through `readAllRows` with\n * `{ count: \"exact\" }` and a stable `.order(\"id\")`, so a truncation is a\n * loud `IncompleteReadError` instead of a confidently short picker.\n * The DB's own favourites-first/`updated_at` order is irrelevant: every row\n * is re-sorted client-side by `sortFilteredAgents`.\n */\n\nimport { readAllRows } from \"@ai-matrx/data/db\";\n\nimport type {\n AgentCatalogClient,\n AgentCatalogFavorites,\n PgErrorLike,\n} from \"./ports\";\nimport { toAgentSummary } from \"./rows\";\nimport type { AgentSummary } from \"./types\";\n\n/** Rows per page. Must not exceed the server's `db-max-rows`. */\nconst LIST_PAGE_SIZE = 1000;\n\n/** Server search page size — the frontend's `AGENT_SEARCH_LIMIT`. */\nexport const AGENT_SEARCH_LIMIT = 50;\n\nexport class AgentCatalogReadError extends Error {\n override readonly name = \"AgentCatalogReadError\";\n readonly source: string;\n constructor(source: string, detail: string) {\n super(`${source}: ${detail}`);\n this.source = source;\n }\n}\n\nfunction pgDetail(error: PgErrorLike): string {\n return error.code ? `${error.message} (${error.code})` : error.message;\n}\n\n/**\n * Read the WHOLE agent catalogue. Throws rather than returning a partial\n * list — see the file header.\n */\nexport async function readAgentCatalogRows(\n client: AgentCatalogClient,\n): Promise<AgentSummary[]> {\n const raw = await readAllRows<unknown>(\n ({ from, to }) =>\n Promise.resolve(\n client\n .rpc(\"agx_get_list_full\", {}, { count: \"exact\" })\n .order(\"id\", { ascending: true })\n .range(from, to),\n ).then((res) => ({\n // `data` crosses a HOST-generated-type boundary, so it arrives as\n // `unknown` and is narrowed here rather than asserted anywhere.\n data: Array.isArray(res.data) ? (res.data as unknown[]) : null,\n error: res.error,\n count: res.count ?? null,\n })),\n { label: \"agx_get_list_full\", pageSize: LIST_PAGE_SIZE },\n );\n\n const rows: AgentSummary[] = [];\n let dropped = 0;\n for (const item of raw) {\n const summary = toAgentSummary(item);\n if (summary) rows.push(summary);\n else dropped += 1;\n }\n if (dropped > 0) {\n throw new AgentCatalogReadError(\n \"agx_get_list_full\",\n `${dropped} row(s) came back without an id and were refused. A row that ` +\n \"cannot be identified cannot be selected, so the catalogue is not \" +\n \"trustworthy — check the RPC's return shape.\",\n );\n }\n return rows;\n}\n\nexport interface AgentServerSearchResult {\n /** Matched ids in SERVER RANK ORDER. */\n ids: string[];\n /** Full rows for every hit — merged additively into the registry. */\n rows: AgentSummary[];\n}\n\n/**\n * Tier-2 server search. Purely ADDITIVE: it widens what the local filter\n * admits and never removes a row the local scorer already matched.\n */\nexport async function searchAgentsOnServer(\n client: AgentCatalogClient,\n args: { query: string; deep?: boolean; limit?: number },\n): Promise<AgentServerSearchResult> {\n const q = args.query.trim();\n if (!q) return { ids: [], rows: [] };\n\n const { data, error } = await client.rpc(\"agx_search\", {\n p_query: q,\n p_deep: args.deep ?? false,\n p_limit: args.limit ?? AGENT_SEARCH_LIMIT,\n p_offset: 0,\n });\n if (error) throw new AgentCatalogReadError(\"agx_search\", pgDetail(error));\n\n const rows: AgentSummary[] = [];\n if (Array.isArray(data)) {\n for (const item of data) {\n const summary = toAgentSummary(item);\n if (summary) rows.push(summary);\n }\n }\n return { ids: rows.map((r) => r.id), rows };\n}\n\n/**\n * The single-agent read, used when a mandate's resolved Holder is not in the\n * caller's own catalogue (a platform agent nobody has shared, most often).\n *\n * Two existing doors, in order — never a new RPC:\n * 1. `agx_search` with the id as the query. The scorer awards an exact id\n * match 100000, so the row comes back first, and it is the FULL 19-column\n * row (name AND description AND category AND tags).\n * 2. `agx_resolve_agent_address([id])` — the frontend's own name resolver.\n * Name and type only, so the row renders with an honest name and no\n * description rather than a fabricated one.\n *\n * Returns `null` when neither door can name the agent. The caller SCREAMS;\n * it never invents a label.\n */\nexport async function readSingleAgentRow(\n client: AgentCatalogClient,\n agentId: string,\n): Promise<AgentSummary | null> {\n try {\n const hit = await searchAgentsOnServer(client, {\n query: agentId,\n limit: 5,\n });\n const exact = hit.rows.find((r) => r.id === agentId);\n if (exact) return exact;\n } catch {\n // Fall through to the address resolver — a search failure is not a verdict.\n }\n\n const { data, error } = await client.rpc(\"agx_resolve_agent_address\", {\n p_ids: [agentId],\n });\n if (error) {\n throw new AgentCatalogReadError(\n \"agx_resolve_agent_address\",\n pgDetail(error),\n );\n }\n if (!Array.isArray(data)) return null;\n for (const item of data) {\n if (typeof item !== \"object\" || item === null) continue;\n const record = item as Record<string, unknown>;\n if (record[\"agent_id\"] !== agentId) continue;\n const name = record[\"agent_name\"];\n return toAgentSummary({\n id: agentId,\n name: typeof name === \"string\" ? name : null,\n agent_type: record[\"agent_type\"],\n is_active: true,\n });\n }\n return null;\n}\n\n/** The `user_entity_state` entity token for an agent. */\nexport const AGENT_FAVORITE_ENTITY_TYPE = \"agent\";\n\n/**\n * Overlay the caller's stars onto freshly-read rows — ONE `ues_get_bulk`\n * round trip for the whole set. Every row's `isFavorite` is set from\n * `platform.user_entity_state` (true iff the caller starred it); nothing the\n * list RPC returned is trusted for it.\n *\n * A failed star read never blocks the catalogue: it is reported (the caller\n * passes `onError`, which the store routes to the errorSink) and every row\n * renders UNSET — an honest \"no stars known\", never a stale column value.\n */\nexport async function overlayAgentFavorites(\n favorites: AgentCatalogFavorites,\n rows: AgentSummary[],\n onError: (message: string) => void,\n): Promise<AgentSummary[]> {\n if (rows.length === 0) return rows;\n let starred: Set<string> | null = null;\n try {\n const result = await favorites.getBulk(\n AGENT_FAVORITE_ENTITY_TYPE,\n rows.map((r) => r.id),\n );\n if (result.ok) {\n starred = new Set(\n result.data.items.filter((s) => s.isFavorite).map((s) => s.entityId),\n );\n } else {\n onError(result.error.message);\n }\n } catch (e) {\n onError(e instanceof Error ? e.message : String(e));\n }\n return rows.map((r) => {\n const isFavorite = starred?.has(r.id) ?? false;\n return r.isFavorite === isFavorite ? r : { ...r, isFavorite };\n });\n}\n\n/**\n * THE ONE WRITE: the caller's star on one agent, in\n * `platform.user_entity_state` through the favorites port. Throws an\n * `AgentCatalogReadError` carrying the refusal in words.\n */\nexport async function writeAgentFavorite(\n favorites: AgentCatalogFavorites,\n agentId: string,\n isFavorite: boolean,\n): Promise<void> {\n const result = await favorites.setFavorite(\n AGENT_FAVORITE_ENTITY_TYPE,\n agentId,\n isFavorite,\n );\n if (!result.ok) {\n throw new AgentCatalogReadError(\n \"user_entity_state (ues_set)\",\n result.error.code\n ? `${result.error.message} (${result.error.code})`\n : result.error.message,\n );\n }\n}\n","/**\n * catalog/rows.ts — @ai-matrx/agents/catalog\n *\n * The ONE ingress for a database row. `agx_get_list_full()` and `agx_search()`\n * return the same list columns (search adds two ranking columns), so both come\n * through here and produce the identical `AgentSummary`.\n *\n * UNKNOWN COLUMNS ARE IGNORED, BY DESIGN. Every column is read by NAME, so an\n * additive platform migration (the way `orchestra` arrived) reaches consumers\n * on `latest` without a package release, and an older database simply yields\n * `null` for a column it does not have yet.\n *\n * Typed over `unknown` on purpose: the truth of this boundary is a\n * HOST-generated Supabase type this package cannot see (the `@ai-matrx/data`\n * 0.2.1 lesson). Narrowing happens here, once, loudly — a row that is not an\n * object is REFUSED rather than half-read.\n */\n\nimport {\n asAgentId,\n type AgentCatalogAgentType,\n type AgentSummary,\n type OrchestraBadge,\n} from \"./types\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction bool(value: unknown): boolean {\n return value === true;\n}\n\nfunction boolOrNull(value: unknown): boolean | null {\n return typeof value === \"boolean\" ? value : null;\n}\n\nfunction stringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter((v): v is string => typeof v === \"string\");\n}\n\n/** `agent_type` is a DB-owned enum; anything but `builtin` is a user agent. */\nfunction agentType(value: unknown): AgentCatalogAgentType {\n return value === \"builtin\" ? \"builtin\" : \"user\";\n}\n\n/**\n * The `orchestra` column, or `null` for an ordinary agent.\n *\n * ADDITIVE-TOLERANT BY CONSTRUCTION: this column arrived after 0.7.x, and a\n * client reading a database that predates it (or a mirror that dropped it)\n * simply sees `null` and shows no badge — never a crash, never a half-badge.\n *\n * `depthBudget` is passed through AS DECLARED and never defaulted: the\n * platform's fallback ceiling belongs to the server that enforces it. A value\n * that is not a positive finite number is not a declaration, so it reads as\n * absent rather than as a number nobody wrote.\n */\nfunction orchestraBadge(value: unknown): OrchestraBadge | null {\n if (!isRecord(value)) return null;\n const depth = value[\"depth_budget\"];\n const count = value[\"member_count\"];\n return {\n mode: str(value[\"mode\"]) ?? \"supervisor\",\n tagline: str(value[\"tagline\"]),\n depthBudget:\n typeof depth === \"number\" && Number.isFinite(depth) && depth > 0\n ? depth\n : null,\n memberCount:\n typeof count === \"number\" && Number.isFinite(count) && count >= 0\n ? count\n : 0,\n memberTitles: stringArray(value[\"member_titles\"]),\n };\n}\n\n/**\n * Map one raw list/search row. Returns `null` when the row is not an object\n * or carries no id — the caller reports that to the errorSink and drops it;\n * a row with no identity cannot be selected, so rendering it would be a lie.\n */\nexport function toAgentSummary(raw: unknown): AgentSummary | null {\n if (!isRecord(raw)) return null;\n const id = str(raw[\"id\"]);\n if (!id) return null;\n\n return {\n id: asAgentId(id),\n name: str(raw[\"name\"]),\n description: str(raw[\"description\"]),\n category: str(raw[\"category\"]),\n tags: stringArray(raw[\"tags\"]),\n agentType: agentType(raw[\"agent_type\"]),\n modelId: str(raw[\"model_id\"]),\n isActive: bool(raw[\"is_active\"]),\n isArchived: bool(raw[\"is_archived\"]),\n // Stars are per-person (platform.user_entity_state) and are overlaid by\n // `overlayAgentFavorites` — a list row never carries the caller's star.\n isFavorite: false,\n createdBy: str(raw[\"created_by\"]),\n organizationId: str(raw[\"organization_id\"]),\n taskId: str(raw[\"task_id\"]),\n sourceAgentId: str(raw[\"source_agent_id\"]),\n createdAt: str(raw[\"created_at\"]),\n updatedAt: str(raw[\"updated_at\"]),\n isOwner: boolOrNull(raw[\"is_owner\"]),\n accessLevel: str(raw[\"access_level\"]),\n sharedByEmail: str(raw[\"shared_by_email\"]),\n orchestra: orchestraBadge(raw[\"orchestra\"]),\n // Present only when the read carries the column: absent ≠ \"no pin\".\n ...(\"offering_id\" in raw ? { offeringId: str(raw[\"offering_id\"]) } : {}),\n };\n}\n","/**\n * catalog/default-row.ts — @ai-matrx/agents/catalog\n *\n * THE DEFAULT ROW, and the drift screamer (design D3).\n *\n * What every client used to do: prepend a placeholder row whose id is\n * `mandate:<key>` and whose name and description are HARDCODED, and let the\n * server resolve the real Holder at run time. That is how matrx-local's row\n * came to be labelled \"Matrx Desktop Agent\" while `local.cloud_chat` actually\n * resolves to General Chat — a label lying on screen, with nothing anywhere\n * that could notice.\n *\n * What happens here instead:\n *\n * - A picker instance passes `defaultMandateKey`. The package resolves the\n * Holder through the aidream door `GET /mandates/{key}/resolution`\n * (verified against `aidream/api/routers/mandate_bindings.py`,\n * `get_mandate_resolution`, mounted at prefix `/mandates`) using the\n * injected `transport`.\n * 🚨 THE PLATFORM RULE D-R1: a client NEVER walks the mandate ladder\n * itself. It asks. That is why a `defaultMandateKey` with no transport is\n * a loud config error and not a DB read.\n * - The row renders the Holder's REAL name and description, read from the\n * catalogue rows already in hand, or through ONE existing single-agent\n * read when the Holder is not in this caller's catalogue.\n * - The last resolution is cached in the `storage` port for first paint.\n * - Whenever the cached row and the LIVE resolution disagree on holder id\n * or holder name, the picker shows a PERSISTENT in-picker banner AND the\n * `notifier` port fires. Never a console line, never only a console line.\n *\n * The row's id stays `mandate:<key>` byte-for-byte, because matrx-extend\n * (`src/lib/mandates.ts`) and matrx-local (`desktop/src/lib/mandates.ts`)\n * already hand that exact ref to their hosts.\n */\n\nimport { readSingleAgentRow } from \"./data\";\nimport type {\n MandateResolutionVerdict,\n ResolvedDefaultRow,\n} from \"./default-row-types\";\nimport type {\n AgentCatalogAsyncStorage,\n AgentCatalogClient,\n AgentCatalogErrorSink,\n AgentCatalogStorage,\n AgentCatalogStorageLike,\n AgentCatalogTransport,\n} from \"./ports\";\nimport { mandateAgentId, type AgentSummary } from \"./types\";\n\nconst CACHE_PREFIX = \"ai-matrx.agents.catalog.default-row:\";\n\nexport class MandateDefaultRowError extends Error {\n override readonly name = \"MandateDefaultRowError\";\n readonly mandateKey: string;\n readonly remedy: string;\n constructor(args: { mandateKey: string; message: string; remedy: string }) {\n super(`${args.message} — ${args.remedy}`);\n this.mandateKey = args.mandateKey;\n this.remedy = args.remedy;\n }\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\n/** Narrow the server's `MandateResolutionResponse` to what a picker needs. */\nexport function parseMandateResolution(\n mandateKey: string,\n raw: unknown,\n): MandateResolutionVerdict {\n if (!isRecord(raw)) {\n throw new MandateDefaultRowError({\n mandateKey,\n message: `mandate \"${mandateKey}\": the resolution endpoint did not return an object`,\n remedy:\n \"check that the transport points at the AI Matrx server and that \" +\n \"GET /mandates/{key}/resolution is reachable\",\n });\n }\n const agentId = raw[\"agent_id\"];\n const definitionAgentId = raw[\"definition_agent_id\"];\n const provenance = raw[\"provenance\"];\n const holderType = raw[\"holder_type\"];\n return {\n mandateKey:\n typeof raw[\"mandate_key\"] === \"string\" ? raw[\"mandate_key\"] : mandateKey,\n holderType: typeof holderType === \"string\" ? holderType : \"agent\",\n agentId: typeof agentId === \"string\" ? agentId : null,\n isVersion: raw[\"is_version\"] === true,\n definitionAgentId:\n typeof definitionAgentId === \"string\" ? definitionAgentId : null,\n provenance: typeof provenance === \"string\" ? provenance : \"system\",\n };\n}\n\nasync function askTheServer(\n transport: AgentCatalogTransport,\n mandateKey: string,\n): Promise<MandateResolutionVerdict> {\n const path = `/mandates/${encodeURIComponent(mandateKey)}/resolution`;\n const response = await transport.fetch(path, {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n if (!response.ok) {\n throw new MandateDefaultRowError({\n mandateKey,\n message: `mandate \"${mandateKey}\": the server refused to resolve it (HTTP ${response.status})`,\n remedy:\n response.status === 404\n ? \"the mandate does not exist — check the key this picker was given\"\n : \"check the caller's session and organization context, then retry\",\n });\n }\n return parseMandateResolution(mandateKey, await response.json());\n}\n\n// ── The first-paint cache ───────────────────────────────────────────────────\n\n/** An in-memory storage, used when the host binds none and there is no DOM. */\nexport function createMemoryStorage(): AgentCatalogStorage {\n const map = new Map<string, string>();\n return {\n getItem: (k) => map.get(k) ?? null,\n setItem: (k, v) => {\n map.set(k, v);\n },\n removeItem: (k) => {\n map.delete(k);\n },\n };\n}\n\n/**\n * DEFAULT storage: `localStorage` when it exists AND answers (a private\n * window, a service worker, or SSR all fail differently), else memory.\n */\nexport function defaultStorage(): AgentCatalogStorage {\n try {\n const ls = (globalThis as { localStorage?: AgentCatalogStorage })\n .localStorage;\n if (ls) {\n const probe = `${CACHE_PREFIX}__probe__`;\n ls.setItem(probe, \"1\");\n ls.removeItem(probe);\n return ls;\n }\n } catch {\n // fall through\n }\n return createMemoryStorage();\n}\n\nexport function readCachedDefaultRow(\n storage: AgentCatalogStorage,\n mandateKey: string,\n): ResolvedDefaultRow | null {\n try {\n const raw = storage.getItem(CACHE_PREFIX + mandateKey);\n if (!raw) return null;\n const parsed: unknown = JSON.parse(raw);\n if (!isRecord(parsed)) return null;\n const holderId = parsed[\"holderId\"];\n const holderName = parsed[\"holderName\"];\n if (typeof holderId !== \"string\" || typeof holderName !== \"string\") {\n return null;\n }\n const description = parsed[\"holderDescription\"];\n const provenance = parsed[\"provenance\"];\n const at = parsed[\"at\"];\n return {\n mandateKey,\n holderId,\n holderName,\n holderDescription: typeof description === \"string\" ? description : null,\n provenance: typeof provenance === \"string\" ? provenance : \"system\",\n at: typeof at === \"number\" ? at : 0,\n };\n } catch {\n return null;\n }\n}\n\nexport function writeCachedDefaultRow(\n storage: AgentCatalogStorage,\n resolved: ResolvedDefaultRow,\n): void {\n try {\n storage.setItem(CACHE_PREFIX + resolved.mandateKey, JSON.stringify(resolved));\n } catch {\n // A full or refusing storage costs a first paint, never correctness.\n }\n}\n\n// ── The async-capable storage seam (0.9.0) ──────────────────────────────────\n//\n// 🚨 THE WEB PATH IS UNCHANGED. Both functions below await whatever the store\n// hands back; a synchronous `localStorage` value is not a promise, so it is\n// already in hand and the behaviour, the cache key and the parse are\n// byte-identical to `readCachedDefaultRow` / `writeCachedDefaultRow` above —\n// which stay exported, and stay synchronous, for every existing caller.\n\n/** Parse whatever the store held under this mandate's key. */\nfunction parseCachedDefaultRow(\n mandateKey: string,\n raw: string | null,\n): ResolvedDefaultRow | null {\n try {\n if (!raw) return null;\n const parsed: unknown = JSON.parse(raw);\n if (!isRecord(parsed)) return null;\n const holderId = parsed[\"holderId\"];\n const holderName = parsed[\"holderName\"];\n if (typeof holderId !== \"string\" || typeof holderName !== \"string\") {\n return null;\n }\n const description = parsed[\"holderDescription\"];\n const provenance = parsed[\"provenance\"];\n const at = parsed[\"at\"];\n return {\n mandateKey,\n holderId,\n holderName,\n holderDescription: typeof description === \"string\" ? description : null,\n provenance: typeof provenance === \"string\" ? provenance : \"system\",\n at: typeof at === \"number\" ? at : 0,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Read the cached row from EITHER storage shape. A store that throws or answers\n * with a rejected promise costs a first paint, never correctness.\n */\nexport async function readCachedDefaultRowAsync(\n storage: AgentCatalogStorageLike,\n mandateKey: string,\n): Promise<ResolvedDefaultRow | null> {\n let raw: string | null;\n try {\n raw = await (storage as AgentCatalogAsyncStorage).getItem(\n CACHE_PREFIX + mandateKey,\n );\n } catch {\n return null;\n }\n return parseCachedDefaultRow(mandateKey, raw);\n}\n\n/** Write the cached row to EITHER storage shape. */\nexport async function writeCachedDefaultRowAsync(\n storage: AgentCatalogStorageLike,\n resolved: ResolvedDefaultRow,\n): Promise<void> {\n try {\n await (storage as AgentCatalogAsyncStorage).setItem(\n CACHE_PREFIX + resolved.mandateKey,\n JSON.stringify(resolved),\n );\n } catch {\n // A full or refusing storage costs a first paint, never correctness.\n }\n}\n\n// ── Building the row ────────────────────────────────────────────────────────\n\n/** Build the `mandate:<key>` row from a resolved Holder. Never hardcodes text. */\nexport function defaultRowFromResolution(\n resolved: ResolvedDefaultRow,\n): AgentSummary {\n return {\n id: mandateAgentId(resolved.mandateKey),\n name: resolved.holderName,\n description: resolved.holderDescription,\n category: null,\n tags: [],\n agentType: \"builtin\",\n modelId: null,\n isActive: true,\n isArchived: false,\n isFavorite: false,\n createdBy: null,\n organizationId: null,\n taskId: null,\n sourceAgentId: resolved.holderId,\n createdAt: null,\n updatedAt: null,\n isOwner: null,\n accessLevel: null,\n sharedByEmail: null,\n // A mandate default row is a live reference to whichever agent the mandate\n // resolves to; the badge belongs to the RESOLVED agent's own catalog row.\n orchestra: null,\n mandateKey: resolved.mandateKey,\n };\n}\n\n/**\n * The drift verdict. Cached vs live: a changed holder id OR a changed holder\n * name is drift. Returns the sentence to show, or `null` when they agree.\n */\nexport function detectDefaultRowDrift(\n cached: ResolvedDefaultRow | null,\n live: ResolvedDefaultRow,\n): string | null {\n if (!cached) return null;\n if (cached.holderId !== live.holderId) {\n return (\n `The default agent for \"${live.mandateKey}\" changed: this screen was ` +\n `showing \"${cached.holderName}\", and the platform now resolves it to ` +\n `\"${live.holderName}\". The list below is correct; anything that cached ` +\n \"the old name is not.\"\n );\n }\n if (cached.holderName !== live.holderName) {\n return (\n `The default agent for \"${live.mandateKey}\" was renamed: \"` +\n `${cached.holderName}\" is now \"${live.holderName}\".`\n );\n }\n return null;\n}\n\nexport interface ResolveDefaultRowArgs {\n mandateKey: string;\n transport: AgentCatalogTransport;\n client: AgentCatalogClient;\n storage: AgentCatalogStorageLike;\n errorSink: AgentCatalogErrorSink;\n /**\n * Look the Holder up in the rows this catalog already holds. May answer\n * asynchronously: the store waits for an in-flight list read before\n * declaring a miss, so a default row never costs a second network read just\n * because the verdict outran the list (the list read now also overlays the\n * caller's stars).\n */\n lookupRow: (\n agentId: string,\n ) => AgentSummary | undefined | Promise<AgentSummary | undefined>;\n}\n\nexport interface ResolveDefaultRowOutcome {\n resolved: ResolvedDefaultRow;\n row: AgentSummary;\n /** Non-null when the cached first-paint row disagreed with the live answer. */\n drift: string | null;\n}\n\n/**\n * Ask the server, name the Holder for real, cache the answer, and report\n * drift. Throws `MandateDefaultRowError` when the mandate cannot produce a\n * runnable agent — a picker never renders a default row it cannot name.\n */\nexport async function resolveDefaultRow(\n args: ResolveDefaultRowArgs,\n): Promise<ResolveDefaultRowOutcome> {\n const { mandateKey, transport, client, storage, lookupRow } = args;\n const cached = await readCachedDefaultRowAsync(storage, mandateKey);\n\n const verdict = await askTheServer(transport, mandateKey);\n\n if (verdict.holderType !== \"agent\") {\n throw new MandateDefaultRowError({\n mandateKey,\n message:\n `mandate \"${mandateKey}\": the ${verdict.provenance} rung names a ` +\n `${verdict.holderType} Holder, and an agent picker can only offer an agent`,\n remedy: `rebind the ${verdict.provenance} rung to an agent, or drop defaultMandateKey from this picker`,\n });\n }\n\n const holderId = verdict.definitionAgentId ?? verdict.agentId;\n if (!holderId) {\n throw new MandateDefaultRowError({\n mandateKey,\n message: `mandate \"${mandateKey}\": the server resolved it without naming an agent`,\n remedy: `bind the ${verdict.provenance} rung to an agent`,\n });\n }\n\n let holder = await lookupRow(holderId);\n if (!holder) {\n holder = (await readSingleAgentRow(client, holderId)) ?? undefined;\n }\n if (!holder || !holder.name) {\n throw new MandateDefaultRowError({\n mandateKey,\n message:\n `mandate \"${mandateKey}\": its Holder resolved, but nothing this ` +\n \"caller can read could name that agent\",\n remedy:\n \"grant this user access to the Holder, or make it a platform agent — \" +\n \"the picker will not print a placeholder name in its place\",\n });\n }\n\n const resolved: ResolvedDefaultRow = {\n mandateKey,\n holderId,\n holderName: holder.name,\n holderDescription: holder.description,\n provenance: verdict.provenance,\n at: Date.now(),\n };\n\n const drift = detectDefaultRowDrift(cached, resolved);\n await writeCachedDefaultRowAsync(storage, resolved);\n\n return { resolved, row: defaultRowFromResolution(resolved), drift };\n}\n","/**\n * catalog/global-state.ts — @ai-matrx/agents/catalog\n *\n * 🚨 MODULE-LEVEL MUTABLE STATE IS BANNED IN THIS PACKAGE. With dual ESM+CJS\n * output and `splitting: false`, each loader graph instantiates its own copy\n * of every module — a module-level variable would silently split the\n * in-flight dedupe (so the \"one RPC for ~20 mounting surfaces\" collapse\n * would become two), the freshness stamp, the catalog registry, and the\n * default-row cache. Everything session-shared therefore lives on\n * `globalThis` under a `Symbol.for` slot, exactly like\n * `@ai-matrx/kit`'s confirm opener. Never \"clean this up\" into module locals.\n */\n\nimport type { ResolvedDefaultRow } from \"./default-row-types\";\n\n/** One session-shared slot for the whole catalog subsystem. */\nconst STATE_SLOT = Symbol.for(\"ai-matrx.agents.catalog\");\n\nexport interface CatalogGlobalState {\n /**\n * Registry of live catalogs by `catalogId`, so a host that imports the\n * package through two loader graphs still gets ONE catalog per id.\n */\n catalogs: Map<string, unknown>;\n /**\n * Shared promise for an in-progress full-list load. Ported from\n * matrx-frontend's `_listFullInFlight`: ~20 surfaces dispatch the load on\n * mount and several co-exist on one page, with their effects running in\n * the same commit — no component-level or status-based guard can see a\n * sibling's request. Sharing the promise collapses them to one\n * `agx_get_list_full` read while every caller still awaits a real result.\n */\n listInFlight: Map<string, Promise<void>>;\n /** Ported from `_chatListFetchedAt` — the TTL guard's stamp. */\n listFetchedAt: Map<string, number>;\n /** Last live default-row resolution per `catalogId::mandateKey`. */\n defaultRows: Map<string, ResolvedDefaultRow>;\n}\n\nexport function getCatalogGlobalState(): CatalogGlobalState {\n const holder = globalThis as Record<symbol, CatalogGlobalState | undefined>;\n let state = holder[STATE_SLOT];\n if (!state) {\n state = {\n catalogs: new Map(),\n listInFlight: new Map(),\n listFetchedAt: new Map(),\n defaultRows: new Map(),\n };\n holder[STATE_SLOT] = state;\n }\n return state;\n}\n\n/** @internal Test-only: forget every session-shared value. */\nexport function _resetCatalogGlobalState(): void {\n const state = getCatalogGlobalState();\n state.catalogs.clear();\n state.listInFlight.clear();\n state.listFetchedAt.clear();\n state.defaultRows.clear();\n}\n","/**\n * catalog/schema.ts — @ai-matrx/agents/catalog\n *\n * THE DEMANDED SCHEMA PROBE (the `@ai-matrx/associations` `assertDemandedSchema`\n * precedent). It proves that the database a host pointed this catalog at can\n * actually answer the functions the picker demands — the three `agx_*` reads\n * and `ues_get_bulk`, the star read (`platform.user_entity_state`).\n *\n * 🚨 IT MUST BE ABLE TO FAIL. A probe whose green result is unconditional\n * proves nothing, so `selfTest: true` also probes a fabricated function name\n * and REQUIRES it to come back missing. `catalog/__tests__/schema.test.ts`\n * runs the whole probe against a client whose `rpc` answers PostgreSQL 42883\n * (`undefined_function`, which PostgREST surfaces as PGRST202) and asserts the\n * loud error.\n */\n\nimport type { AgentCatalogClient } from \"./ports\";\n\n/** A UUID that cannot exist, so a probe never touches a real row. */\nconst BAD_UUID = \"00000000-0000-0000-0000-000000000000\";\n\nconst SELF_TEST_MISSING_RPC = \"agx_this_function_does_not_exist_probe\";\n\n/** The functions the catalog cannot work without, and safe probe arguments. */\nconst DEMANDED_RPCS: Record<string, Record<string, unknown>> = {\n agx_get_list_full: {},\n agx_search: { p_query: \"__probe__\", p_deep: false, p_limit: 1, p_offset: 0 },\n agx_resolve_agent_address: { p_ids: [BAD_UUID] },\n // The caller's stars. Read-only, and an impossible id touches no row.\n ues_get_bulk: { p_entity_type: \"agent\", p_entity_ids: [BAD_UUID] },\n};\n\nexport interface AgentCatalogSchemaReport {\n ok: boolean;\n /** Demanded functions the database cannot answer. */\n missing: string[];\n /** Functions the probe could not reach (transport/unknown failure). */\n unreachable: { fn: string; error: unknown }[];\n /** Functions that answered (success or any non-missing refusal). */\n answered: string[];\n /**\n * Whether `agx_get_list_full` carries the `orchestra` badge column (added to\n * the platform 2026-09-08).\n *\n * NOT a violation when absent — the picker degrades to no conductor marker,\n * which is honest — but it is never SILENT either: a `false` here is the one\n * signal that tells a host \"this database predates the badge\" instead of\n * leaving someone to wonder why their Orchestra looks like a plain agent.\n * `null` means the probe could not tell (the caller can see no agents at\n * all), never \"fine\".\n */\n orchestraColumn: boolean | null;\n}\n\nexport interface AssertAgentCatalogSchemaOptions {\n /**\n * Also probe a fabricated function name and REQUIRE it to come back\n * missing — proves this probe can fail.\n */\n selfTest?: boolean;\n /** Return the report instead of throwing. The self-test failure ALWAYS throws. */\n throwOnViolation?: boolean;\n}\n\n/**\n * PostgREST reports an unknown function as PGRST202; PostgreSQL's own SQLSTATE\n * for it is 42883. Both are accepted so this probe works through PostgREST AND\n * through any client that surfaces the raw SQLSTATE.\n */\nfunction isMissingFunctionError(error: unknown): boolean {\n if (!error || typeof error !== \"object\") return false;\n const code = (error as { code?: unknown }).code;\n return code === \"PGRST202\" || code === \"42883\";\n}\n\n/**\n * Probe every demanded function. Throws an `Error` naming each missing one\n * (unless `throwOnViolation: false`), and ALWAYS throws when the probe itself\n * cannot be trusted (unreachable database, failed self-test).\n */\nexport async function assertAgentCatalogSchema(\n client: AgentCatalogClient,\n options: AssertAgentCatalogSchemaOptions = {},\n): Promise<AgentCatalogSchemaReport> {\n const { selfTest = false, throwOnViolation = true } = options;\n\n const names = Object.keys(DEMANDED_RPCS);\n if (selfTest) names.push(SELF_TEST_MISSING_RPC);\n\n const missing: string[] = [];\n const unreachable: { fn: string; error: unknown }[] = [];\n const answered: string[] = [];\n let orchestraColumn: boolean | null = null;\n\n for (const fn of names) {\n const args = DEMANDED_RPCS[fn] ?? {};\n try {\n const { data, error } = await client.rpc(fn, args);\n if (fn === \"agx_get_list_full\" && error == null) {\n orchestraColumn = readsOrchestraColumn(data);\n }\n if (error == null) answered.push(fn);\n else if (isMissingFunctionError(error)) missing.push(fn);\n else answered.push(fn);\n } catch (e) {\n unreachable.push({ fn, error: e });\n }\n }\n\n if (selfTest) {\n const selfTestMissing = missing.includes(SELF_TEST_MISSING_RPC);\n const idx = missing.indexOf(SELF_TEST_MISSING_RPC);\n if (idx >= 0) missing.splice(idx, 1);\n const answeredIdx = answered.indexOf(SELF_TEST_MISSING_RPC);\n if (answeredIdx >= 0) answered.splice(answeredIdx, 1);\n if (!selfTestMissing) {\n throw new Error(\n \"assertAgentCatalogSchema self-test FAILED: the fabricated function \" +\n `\"${SELF_TEST_MISSING_RPC}\" did not come back as missing. This probe ` +\n \"cannot currently fail, so its green result proves nothing — the \" +\n \"client is swallowing or faking errors.\",\n );\n }\n }\n\n if (unreachable.length > 0) {\n throw new Error(\n \"assertAgentCatalogSchema could not complete: \" +\n `${unreachable.length} probe call(s) failed to reach the database (` +\n `${unreachable.map((u) => u.fn).join(\", \")}). This is NOT a schema ` +\n \"verdict — fix connectivity and re-run.\",\n );\n }\n\n const ok = missing.length === 0;\n const report: AgentCatalogSchemaReport = {\n ok,\n missing,\n unreachable,\n answered,\n orchestraColumn,\n };\n\n if (!ok && throwOnViolation) {\n throw new Error(\n \"DEMANDED SCHEMA VIOLATION: the database this client points at \" +\n `cannot answer ${missing.length} demanded function(s): ` +\n `${missing.join(\", \")}. @ai-matrx/agents/catalog cannot render a ` +\n \"correct picker against it — point the client at Matrx Main, or apply \" +\n \"the agx_* migrations.\",\n );\n }\n\n return report;\n}\n\n/**\n * `true` when the list rows carry the `orchestra` key, `false` when there ARE\n * rows and none does, `null` when there is nothing to judge from. Reads the\n * KEY, not its value: a conductorless account still proves the column exists.\n */\nfunction readsOrchestraColumn(data: unknown): boolean | null {\n if (!Array.isArray(data) || data.length === 0) return null;\n return data.some(\n (row) =>\n typeof row === \"object\" &&\n row !== null &&\n Object.prototype.hasOwnProperty.call(row, \"orchestra\"),\n );\n}\n","/**\n * catalog/orchestra.ts — @ai-matrx/agents/catalog\n *\n * Creator words for an Orchestra badge. A VERBATIM port of the helpers the\n * Workflow Studio's hand-rolled picker carried (`apps/workflow-studio/src/\n * hooks/use-agents.ts` before `c0f958b43`), lifted here so every client says\n * the same sentence about the same ensemble.\n *\n * Pure — no React, no DOM. The row shape is `OrchestraBadge` in `./types`.\n */\n\nimport type { OrchestraBadge } from \"./types\";\n\n/**\n * Creator words for an Orchestra's run mode. \"supervisor\" is already plain\n * English; the structural modes get humanized (never \"sequential/parallel/dag\"\n * at eye level). An unknown future mode falls through as its own word rather\n * than hiding — visible-but-unpolished beats invisible.\n */\nconst ORCHESTRA_MODE_LABEL: Record<string, string> = {\n supervisor: \"supervisor\",\n sequential: \"in order\",\n parallel: \"together\",\n dag: \"custom flow\",\n};\n\nexport function orchestraModeLabel(mode: string): string {\n return ORCHESTRA_MODE_LABEL[mode] ?? mode;\n}\n\n/** Human label for a badge: \"Orchestra · supervisor · 3 members\" (singular-safe). */\nexport function orchestraLabel(badge: OrchestraBadge): string {\n const n = badge.memberCount;\n return `Orchestra · ${orchestraModeLabel(badge.mode)} · ${n} ${\n n === 1 ? \"member\" : \"members\"\n }`;\n}\n\n/**\n * The member-call ceiling in Creator language (\"Team members can call helpers\n * up to 2 levels deep\"), or `null` when the composition declared none. A badge\n * never invents the platform default: the server that runs the ensemble owns\n * that number, and printing a promise nobody made is worse than printing\n * nothing.\n */\nexport function orchestraDepthLine(badge: OrchestraBadge): string | null {\n const n = badge.depthBudget;\n if (typeof n !== \"number\" || n <= 0) return null;\n return `Team members can call helpers up to ${n} ${\n n === 1 ? \"level\" : \"levels\"\n } deep`;\n}\n\n/**\n * One visible line naming who the Orchestra delegates to, collapsing past\n * `limit` into \"+N more\". `null` when no member carries a real role title —\n * \"Member, Member, Member\" is noise that reads like data.\n */\nexport function orchestraDelegatesLine(\n badge: OrchestraBadge,\n limit = 3,\n): string | null {\n const titles = badge.memberTitles;\n if (titles.length === 0) return null;\n const shown = titles.slice(0, limit);\n const extra = titles.length - shown.length;\n return `Delegates to: ${shown.join(\", \")}${\n extra > 0 ? ` +${extra} more` : \"\"\n }`;\n}\n","/**\n * catalog/labels.ts — @ai-matrx/agents/catalog\n *\n * VERBATIM port of matrx-frontend `features/agents/constants/agent-list-labels.ts`.\n * The only seam inverted: the two label constants moved into the `labels` port\n * (`DEFAULT_AGENT_CATALOG_LABELS.publicTab` / `.publicBadge`) so a host can\n * override them; the FUNCTIONS below keep their exact behaviour.\n */\n\nimport type { AgentCatalogLabels } from \"./ports\";\nimport { ARCHIVE_FILTER_OPTIONS, nextArchFilter } from \"./types\";\nimport type { AgentArchFilter, AgentTab } from \"./types\";\n\nexport function agentListEmptyLabel(\n tab: AgentTab,\n labels: AgentCatalogLabels,\n): string {\n switch (tab) {\n case \"system\":\n // 🚨 The tab IS the system tab, and the surfaces that mount this picker\n // call that rung \"System\" (V1 round 3). Saying \"public\" here made the\n // empty state name a different thing from the rung the person had just\n // chosen. The tab's own LABEL is a wider vocabulary question and is left\n // alone — this only stops the empty state contradicting its own case.\n return labels.emptySystem;\n case \"shared\":\n return labels.emptyShared;\n default:\n return labels.emptyDefault;\n }\n}\n\n/** Whether a list picker should default to the public (`system`) tab instead of Mine. */\nexport function shouldDefaultAgentListToPublicTab(args: {\n userId: string | null;\n ownedCount: number;\n agentsLoaded: boolean;\n}): boolean {\n if (!args.userId) return true;\n if (!args.agentsLoaded) return false;\n return args.ownedCount === 0;\n}\n\n// ── THE ARCHIVED-ITEMS LAW — the control's words, and the honest footer ─────\n//\n// `common-docs/policies/archived-items.md`, Arman 2026-09-09:\n//\n// \"everything should have an archive filter, and the default should always\n// hide archived, but seeing archived items should be one or two clicks\n// away.\"\n//\n// Clause 2 of that law is why these live here rather than inside a component:\n// \"Counts, badges, footers and pagination count what the list renders — a\n// screen never lies.\" The footer string is computed ONCE, from the same\n// numbers the list rendered, for both platforms.\n\n/** What the filter-bar chip reads in each state. */\nexport function agentArchiveFilterChipLabel(archFilter: AgentArchFilter): string {\n return (\n ARCHIVE_FILTER_OPTIONS.find((o) => o.value === archFilter)?.chip ?? \"Archive\"\n );\n}\n\n/** The platform's words for the state — menus, aria-labels, help text. */\nexport function agentArchiveFilterStateLabel(\n archFilter: AgentArchFilter,\n): string {\n return (\n ARCHIVE_FILTER_OPTIONS.find((o) => o.value === archFilter)?.label ??\n \"Hide archived\"\n );\n}\n\n/**\n * The accessible name of the ONE control, always naming the state it is IN\n * and the state one click moves it to. A control whose label does not say\n * what it currently does is the \"dead or dishonest\" shape the platform bans.\n */\nexport function agentArchiveFilterControlLabel(\n archFilter: AgentArchFilter,\n): string {\n return `Archive filter: ${agentArchiveFilterStateLabel(\n archFilter,\n ).toLowerCase()}. Click for ${agentArchiveFilterStateLabel(\n nextArchFilter(archFilter),\n ).toLowerCase()}`;\n}\n\n/**\n * THE FOOTER. It counts exactly what the list rendered and, whenever archived\n * rows are involved, says so — hidden ones included.\n *\n * hide archived, nothing archived behind it → \"412 agents\"\n * hide archived, 4 archived behind it → \"412 agents · 4 archived hidden\"\n * show all → \"416 agents · archived shown\"\n * archived only → \"4 archived shown\"\n */\nexport function agentListFooterLabel(args: {\n /** Rows actually rendered. */\n count: number;\n archFilter: AgentArchFilter;\n /**\n * Rows this view WOULD render if the filter were flipped to \"archived only\"\n * — exactly what the default state is keeping off the screen. Only ever\n * read in the `active` state.\n */\n archivedHiddenCount: number;\n}): string {\n const { count, archFilter, archivedHiddenCount } = args;\n if (archFilter === \"archived\") return `${count} archived shown`;\n const base = `${count} agent${count !== 1 ? \"s\" : \"\"}`;\n if (archFilter === \"both\") return `${base} · archived shown`;\n return archivedHiddenCount > 0\n ? `${base} · ${archivedHiddenCount} archived hidden`\n : base;\n}\n","// catalog/score.ts — @ai-matrx/agents/catalog\n//\n// THE canonical agent relevance scorer. One implementation, every surface,\n// every APP. Ported VERBATIM (behaviour byte-for-byte) from matrx-frontend\n// `features/agents/search/score.ts`; only the file header changed.\n//\n// This existed twice with drifted weights — the gallery copy in\n// `features/agents/redux/agent-consumers/selectors.ts` and a chat-side copy in\n// the (deleted 2026-08) legacy agentCache selectors. The chat copy scored an id\n// match at 50 with no exact-id bonus, so searching a chat-side picker by UUID\n// was effectively dead. Everything now delegates here.\n//\n// Pure: no Redux, no store types, no imports. Anything that can describe an\n// agent structurally can be scored.\n//\n// Adding a field? Add it here and it lights up on every surface at once.\n// Never fork this function.\n//\n// ── SQL PARITY (load-bearing) ───────────────────────────────────────────────\n// `public.agx_search_score` in migrations/agx_search_score.sql is the SQL\n// mirror of this function. Server-side paging FORCES a second implementation —\n// relevance has to be computed before LIMIT, which the browser cannot do — but\n// the two must stay in lockstep.\n//\n// CHANGE ONE, CHANGE THE OTHER IN THE SAME COMMIT, and keep the weights below\n// identical to the SQL constants. Guarded by score.parity.test.ts against the\n// shared fixture in __fixtures__/search-score-parity.json.\n//\n// This is not hypothetical: /agents/all shipped with a flat SQL `ILIKE OR` and\n// no ranking at all, so a description match tied with a name match and\n// searching \"image\" buried every image agent under unrelated ones.\n\n/**\n * The structural shape a record needs to be searchable. Every field except\n * `id` is optional so both the full gallery record and the slim chat record\n * satisfy it without adapters.\n */\nexport interface AgentSearchable {\n id: string;\n name?: string | null;\n description?: string | null;\n category?: string | null;\n tags?: string[] | null;\n modelId?: string | null;\n agentType?: string | null;\n outputFormat?: string | null;\n sharedByEmail?: string | null;\n}\n\n/**\n * Relevance score for an agent against a query. Higher = more relevant.\n * Returns 0 when nothing matches (0 is the \"no match\" contract — see\n * `agentMatchesSearch`).\n *\n * Scores only fields carried by the list-level fetches. Message content and\n * variable definitions are deliberately excluded: they are not loaded by the\n * list RPCs, so matching them here would be a false promise. Server-side\n * search owns deep content matching.\n */\nexport function computeAgentSearchScore(\n agent: AgentSearchable,\n query: string,\n): number {\n const q = query.trim().toLowerCase();\n if (!q) return 0;\n\n let score = 0;\n\n const name = (agent.name ?? \"\").toLowerCase();\n const desc = (agent.description ?? \"\").toLowerCase();\n\n if (name === q) score += 10000;\n else if (name.startsWith(q)) score += 5000;\n // Word-boundary beats a mid-word substring: \"image\" ranks\n // \"Basic Image Generator\" above \"Reimagine Helper\".\n else if (matchesWholeWord(name, q)) score += 3000;\n else if (name.includes(q)) score += 2000;\n\n if (desc === q) score += 1000;\n else if (desc.includes(q)) score += 500;\n\n if (agent.category?.toLowerCase().includes(q)) score += 300;\n if (agent.tags?.some((t) => t.toLowerCase().includes(q))) score += 300;\n if (agent.modelId?.toLowerCase().includes(q)) score += 100;\n if (agent.agentType?.toLowerCase().includes(q)) score += 100;\n if (agent.outputFormat?.toLowerCase().includes(q)) score += 100;\n\n // Id search — an exact UUID always wins outright so you can paste an id from\n // a URL or a log line and land on that agent, on any surface.\n const id = agent.id.toLowerCase();\n if (id === q) score += 100000;\n else if (id.includes(q)) score += 5000;\n\n // Helps find agents shared by a specific person.\n if (agent.sharedByEmail?.toLowerCase().includes(q)) score += 200;\n\n // Multi-term fallback: \"image gen\" matches nothing as a phrase. Score per\n // TERM, and only when EVERY term lands somewhere — so multi-word searches\n // work without degrading into a loose OR that matches half the list.\n if (score === 0 && q.includes(\" \")) {\n const terms = q.split(/\\s+/).filter(Boolean);\n let hits = 0;\n let termScore = 0;\n for (const term of terms) {\n const inName = name.includes(term);\n const matched =\n inName ||\n desc.includes(term) ||\n (agent.category?.toLowerCase().includes(term) ?? false) ||\n (agent.tags?.some((t) => t.toLowerCase().includes(term)) ?? false);\n if (matched) {\n hits += 1;\n termScore += inName ? 400 : 100;\n }\n }\n // All-or-nothing: a partial term match is not a match.\n if (hits === terms.length) score += termScore;\n }\n\n return score;\n}\n\n/** True when `q` appears in `haystack` on word boundaries. */\nfunction matchesWholeWord(haystack: string, q: string): boolean {\n const escaped = q.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return new RegExp(`\\\\b${escaped}\\\\b`).test(haystack);\n}\n\n/** True when the agent matches the query at all. */\nexport function agentMatchesSearch(\n agent: AgentSearchable,\n query: string,\n): boolean {\n return computeAgentSearchScore(agent, query) > 0;\n}\n","/**\n * catalog/selectors.ts — @ai-matrx/agents/catalog\n *\n * VERBATIM port of matrx-frontend\n * `features/agents/redux/agent-consumers/selectors.ts`.\n *\n * ALL filter, sort, search-scoring, category/tag extraction and pagination\n * logic lives here — not in components. Two coupling seams inverted, nothing\n * else:\n *\n * 1. `createSelector` (reselect) → `memoize1`/`memoize2`/`memoize3` below,\n * the same last-arguments reference-equality memoization reselect\n * defaults to. No Redux, no store types.\n * 2. `AgentDefinitionRecord` → `AgentSummary`, the list-row shape\n * `agx_get_list_full` actually returns.\n *\n * One structural consequence of (2), recorded rather than hidden: the\n * frontend's `selectLiveAgents` filters `isVersion` snapshots out of a store\n * that also holds them. This catalog only ever holds list rows — a version\n * snapshot cannot enter it — so that filter is a no-op here and is not\n * ported.\n *\n * 🚨 TWO DELIBERATE DEPARTURES FROM THE ORIGINAL, both defects the port\n * inherited and 0.9.1 fixes at the class (see CHANGELOG 0.9.1):\n *\n * F1 — every sort now ends on `id` ASC, the same final key `agx_get_list`\n * ends on, so the order of TIED rows is defined by the rows instead of\n * by whichever transport the host used to fetch them.\n * F5 — the tab-badge counts honour the archive filter, so the badge, the\n * footer and the rendered rows are the same number.\n *\n * Everything else below is byte-identical to the original.\n */\n\nimport {\n agentMatchesSearch,\n computeAgentSearchScore,\n} from \"./score\";\nimport {\n AGENT_NONE_SENTINEL,\n type AgentArchFilter,\n type AgentConsumerState,\n type AgentSortOption,\n type AgentSummary,\n} from \"./types\";\n\nexport { computeAgentSearchScore, agentMatchesSearch };\nexport { AGENT_NONE_SENTINEL };\n\n// ── Constants (verbatim) ─────────────────────────────────────────────────────\n\nexport const AGENT_CARDS_LIMIT_DESKTOP = 8;\nexport const AGENT_CARDS_LIMIT_MOBILE = 4;\nexport const AGENT_LIST_ITEMS_PER_PAGE = 20;\n\n// ── Memoization (the reselect seam, inverted) ───────────────────────────────\n\n/**\n * Last-arguments memoization on reference equality — reselect's default\n * `defaultMemoize` behaviour, in eleven lines and with no dependency. A\n * selector built here is memoized PER INSTANCE, exactly like a\n * `createSelector` result, so the factories below keep their contract:\n * build the selector once per (consumerId, …) and reuse it.\n */\nexport function memoize1<A, R>(fn: (a: A) => R): (a: A) => R {\n let lastA: A | undefined;\n let last: R;\n let has = false;\n return (a: A): R => {\n if (!has || lastA !== a) {\n last = fn(a);\n lastA = a;\n has = true;\n }\n return last;\n };\n}\n\nexport function memoize2<A, B, R>(fn: (a: A, b: B) => R): (a: A, b: B) => R {\n let lastA: A | undefined;\n let lastB: B | undefined;\n let last: R;\n let has = false;\n return (a: A, b: B): R => {\n if (!has || lastA !== a || lastB !== b) {\n last = fn(a, b);\n lastA = a;\n lastB = b;\n has = true;\n }\n return last;\n };\n}\n\nexport function memoize3<A, B, C, R>(\n fn: (a: A, b: B, c: C) => R,\n): (a: A, b: B, c: C) => R {\n let lastA: A | undefined;\n let lastB: B | undefined;\n let lastC: C | undefined;\n let last: R;\n let has = false;\n return (a: A, b: B, c: C): R => {\n if (!has || lastA !== a || lastB !== b || lastC !== c) {\n last = fn(a, b, c);\n lastA = a;\n lastB = b;\n lastC = c;\n has = true;\n }\n return last;\n };\n}\n\n// ── Pure sort comparator ────────────────────────────────────────────────────\n\n/**\n * 🚨 THE FINAL TIEBREAKER. `agx_get_list` orders\n * `is_favorite DESC, updated_at DESC, id` — `id` ASCENDING is the unique key\n * that makes the SERVER's order TOTAL. Every sort in this file ends on the\n * same key, so the rendered order is a function of the ROWS and never of the\n * order they happened to arrive in.\n *\n * Why a raw `<` / `>` and not `localeCompare`: Postgres orders `uuid` by its\n * 16 raw bytes. The canonical text form is lowercase hex with dashes at fixed\n * positions, so a codepoint comparison of those strings reproduces the\n * database's order exactly. A locale collator does not — it is free to fold\n * case or ignore punctuation, and would silently diverge from the server on\n * precisely the ties this key exists to settle.\n */\nexport function compareAgentIds(a: AgentSummary, b: AgentSummary): number {\n const idA = a.id ?? \"\";\n const idB = b.id ?? \"\";\n if (idA < idB) return -1;\n if (idA > idB) return 1;\n return 0;\n}\n\n/**\n * The chosen sort key, then `id`. TOTAL for every option.\n *\n * Before 0.9.1 each branch below returned 0 for tied rows, which left their\n * relative order to whatever `Array.prototype.sort` had been handed — i.e. to\n * the transport. A host that fetched the RPC in one shot kept the server's\n * favourites-first/`updated_at DESC` order for ties; a host that paged it with\n * `order=id.asc` kept id-ASC. Same rows, same filters, two different screens.\n * The key below is the server's own, so both now render the server's answer.\n */\nexport function applyAgentSortComparator(\n a: AgentSummary,\n b: AgentSummary,\n sortBy: AgentSortOption,\n): number {\n const primary = compareAgentSortKey(a, b, sortBy);\n // An unparseable timestamp yields NaN, which `sort` reads as \"equal\" while\n // defeating `!== 0`. Collapse it to a tie so the id key still decides — a\n // total order must not depend on the data being clean.\n if (!Number.isFinite(primary) || primary === 0) return compareAgentIds(a, b);\n return primary;\n}\n\n/** The chosen key ALONE — no tiebreaker. Not total; not for rendering. */\nfunction compareAgentSortKey(\n a: AgentSummary,\n b: AgentSummary,\n sortBy: AgentSortOption,\n): number {\n switch (sortBy) {\n case \"name-asc\":\n return (a.name ?? \"\").localeCompare(b.name ?? \"\");\n case \"name-desc\":\n return (b.name ?? \"\").localeCompare(a.name ?? \"\");\n case \"created-desc\":\n return +new Date(b.createdAt ?? 0) - +new Date(a.createdAt ?? 0);\n case \"category-asc\":\n return (a.category ?? \"\").localeCompare(b.category ?? \"\");\n case \"updated-desc\":\n default:\n return +new Date(b.updatedAt ?? 0) - +new Date(a.updatedAt ?? 0);\n }\n}\n\n// ── Category / tag metadata (derived from live agents) ──────────────────────\n\n/** All unique categories across live USER agents, sorted alphabetically. */\nexport const selectAllAgentCategories = memoize1(\n (agents: readonly AgentSummary[]): string[] => {\n const cats = new Set<string>();\n for (const a of agents) {\n if (a.agentType === \"user\" && a.category) cats.add(a.category);\n }\n return Array.from(cats).sort();\n },\n);\n\n/**\n * All unique categories across live SYSTEM (builtin) agents. The system tab\n * gets the same category filter every other tab has — its options just come\n * from a different population.\n */\nexport const selectAllSystemAgentCategories = memoize1(\n (agents: readonly AgentSummary[]): string[] => {\n const cats = new Set<string>();\n for (const a of agents) {\n if (a.agentType === \"builtin\" && a.category) cats.add(a.category);\n }\n return Array.from(cats).sort();\n },\n);\n\n/** All unique tags across live user agents, sorted alphabetically. */\nexport const selectAllAgentTags = memoize1(\n (agents: readonly AgentSummary[]): string[] => {\n const tags = new Set<string>();\n for (const a of agents) {\n if (a.agentType === \"user\") a.tags?.forEach((t) => tags.add(t));\n }\n return Array.from(tags).sort();\n },\n);\n\n/** All unique tags across live SYSTEM (builtin) agents. */\nexport const selectAllSystemAgentTags = memoize1(\n (agents: readonly AgentSummary[]): string[] => {\n const tags = new Set<string>();\n for (const a of agents) {\n if (a.agentType === \"builtin\") a.tags?.forEach((t) => tags.add(t));\n }\n return Array.from(tags).sort();\n },\n);\n\n// ── User-owned + shared agents (excludes builtins) ─────────────────────────\n\n/** Live user-type agents (excludes builtins). */\nexport const selectUserTypeAgents = memoize1(\n (agents: readonly AgentSummary[]): AgentSummary[] =>\n agents.filter((a) => a.agentType === \"user\"),\n);\n\n/** Builtin/system agents only. For chat pickers and full catalogues. */\nexport const selectBuiltinTypeAgents = memoize1(\n (agents: readonly AgentSummary[]): AgentSummary[] =>\n agents.filter((a) => a.agentType === \"builtin\"),\n);\n\n// ── Pure filter pipelines (verbatim) ───────────────────────────────────────\n\n/**\n * The ONE ordering rule, and it is TOTAL on every path.\n *\n * searching: score DESC → server rank ASC → sort key → id ASC\n * not searching: favourites first (when asked) → sort key → id ASC\n *\n * `id` ASC is the final key `agx_get_list` itself ends on, so two hosts that\n * fetched the same rows through different transports render the same screen.\n */\nexport function sortFilteredAgents(\n filtered: AgentSummary[],\n consumer: AgentConsumerState,\n): AgentSummary[] {\n const { searchTerm, sortBy, favFilter, favoritesFirst } = consumer;\n\n if (searchTerm) {\n const scores = new Map<string, number>();\n filtered.forEach((a) => {\n scores.set(a.id, computeAgentSearchScore(a, searchTerm));\n });\n\n // Server rank, used only to order matches the local scorer cannot see\n // (tier-2 prompt hits). Locally-scored matches all have score > 0, so\n // they sort above this group unconditionally — obvious matches first.\n const serverRank = new Map<string, number>();\n consumer.serverMatchedIds.forEach((id, i) => serverRank.set(id, i));\n\n return [...filtered].sort((a, b) => {\n const sa = scores.get(a.id) ?? 0;\n const sb = scores.get(b.id) ?? 0;\n if (sb !== sa) return sb - sa;\n if (sa === 0) {\n const ra = serverRank.get(a.id);\n const rb = serverRank.get(b.id);\n if (ra !== undefined && rb !== undefined && ra !== rb) return ra - rb;\n }\n return applyAgentSortComparator(a, b, sortBy);\n });\n }\n\n return [...filtered].sort((a, b) => {\n if (favoritesFirst && favFilter === \"all\") {\n const aFav = a.isFavorite ? 1 : 0;\n const bFav = b.isFavorite ? 1 : 0;\n if (bFav !== aFav) return bFav - aFav;\n }\n return applyAgentSortComparator(a, b, sortBy);\n });\n}\n\n/** User-type agents — mine / shared / all tabs with full consumer filters. */\nexport function filterUserTypeAgents(\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n): AgentSummary[] {\n const {\n searchTerm,\n includedCats,\n includedTags,\n favFilter,\n archFilter,\n accessFilter,\n tab,\n } = consumer;\n\n // Built once, not per row — this runs on every keystroke over the full list.\n const serverMatched = new Set(consumer.serverMatchedIds);\n\n const filtered = agents.filter((agent) => {\n if (tab === \"mine\" && agent.isOwner !== true) return false;\n if (\n tab === \"shared\" &&\n !(agent.isOwner === false && agent.accessLevel != null)\n )\n return false;\n\n // THE ARCHIVED-ITEMS LAW, through the ONE predicate every tab, badge and\n // footer in this package shares.\n if (!agentMatchesArchiveFilter(agent, archFilter)) return false;\n\n if (favFilter === \"yes\" && !agent.isFavorite) return false;\n if (favFilter === \"no\" && agent.isFavorite) return false;\n\n if (accessFilter === \"owned\" && agent.isOwner !== true) return false;\n if (accessFilter === \"shared\" && agent.isOwner !== false) return false;\n if (\n accessFilter === \"editable\" &&\n agent.accessLevel !== \"owner\" &&\n agent.accessLevel !== \"admin\" &&\n agent.accessLevel !== \"editor\"\n )\n return false;\n\n if (includedCats.length > 0) {\n const category = agent.category;\n if (!category) {\n if (!includedCats.includes(AGENT_NONE_SENTINEL)) return false;\n } else if (!includedCats.includes(category)) {\n return false;\n }\n }\n\n if (includedTags.length > 0) {\n const isUntagged = !agent.tags?.length;\n if (isUntagged) {\n if (!includedTags.includes(AGENT_NONE_SENTINEL)) return false;\n } else if (!agent.tags?.some((t) => includedTags.includes(t))) {\n return false;\n }\n }\n\n // A server hit counts as a match even when the local scorer scores 0 —\n // that is the only way tier-2 prompt matches can reach the screen, since\n // the client never loads prompt content to score against.\n if (\n searchTerm &&\n !agentMatchesSearch(agent, searchTerm) &&\n !serverMatched.has(agent.id)\n )\n return false;\n\n return true;\n });\n\n return sortFilteredAgents(filtered, consumer);\n}\n\n/**\n * Builtin/system agents (tab === \"system\").\n *\n * Gets the SAME filter surface every other tab has — search, favorites,\n * category, tags, sort, AND THE ARCHIVE FILTER. Only the ownership/access\n * filters are skipped, because a builtin has no owner to filter on. A picker\n * that offers less on one tab than another is the exact half-built shape this\n * list exists to prevent.\n *\n * 🚨 0.9.2 — THE BUILTIN ARCHIVE EXEMPTION IS GONE, AND IT IS NOW ILLEGAL.\n *\n * Until 0.9.1 this function applied no archive filter, on the theory that \"a\n * builtin belongs to the platform and is never the user's to archive\". The\n * database disagreed: `Foundry Planner`\n * (`001b22f6-fa4d-40c6-a1a4-8575d4d04379`) is an ARCHIVED builtin, and it\n * rendered at Public index 216 and was pickable — while Mine / Shared / All\n * hid their archived rows. One picker, two rules, and a person could choose a\n * retired agent from the one tab that did not obey.\n *\n * THE ARCHIVED-ITEMS LAW (`common-docs/policies/archived-items.md`, Arman\n * 2026-09-09) closed the question for every entity at once: \"everything should\n * have an archive filter, and the default should always hide archived… all\n * archived items should always be treated the same.\" Clause 4 makes it a\n * class, not an instance — so there is no per-tab, per-entity or per-surface\n * exemption left to grant, here or anywhere.\n */\nexport function filterBuiltinTypeAgents(\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n): AgentSummary[] {\n const { searchTerm, favFilter, archFilter, includedCats, includedTags } =\n consumer;\n const serverMatched = new Set(consumer.serverMatchedIds);\n\n const filtered = agents.filter((agent) => {\n // THE LAW, first and unconditional — identical to the user-tab rule above.\n if (!agentMatchesArchiveFilter(agent, archFilter)) return false;\n\n if (favFilter === \"yes\" && !agent.isFavorite) return false;\n if (favFilter === \"no\" && agent.isFavorite) return false;\n\n if (includedCats.length > 0) {\n const category = agent.category;\n if (!category) {\n if (!includedCats.includes(AGENT_NONE_SENTINEL)) return false;\n } else if (!includedCats.includes(category)) {\n return false;\n }\n }\n\n if (includedTags.length > 0) {\n const isUntagged = !agent.tags?.length;\n if (isUntagged) {\n if (!includedTags.includes(AGENT_NONE_SENTINEL)) return false;\n } else if (!agent.tags?.some((t) => includedTags.includes(t))) {\n return false;\n }\n }\n\n if (\n searchTerm &&\n !agentMatchesSearch(agent, searchTerm) &&\n !serverMatched.has(agent.id)\n )\n return false;\n\n return true;\n });\n\n return sortFilteredAgents(filtered, consumer);\n}\n\n// ── Filtered agents (user + system tabs) ───────────────────────────────────\n\n/** Factory: owned user-type agents with consumer filters applied (ignores tab). */\nexport const makeSelectFilteredOwnedAgents = () =>\n memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentSummary[] =>\n filterUserTypeAgents(selectUserTypeAgents(agents), {\n ...consumer,\n tab: \"mine\",\n }),\n );\n\n/** Factory: shared user-type agents with consumer filters applied (ignores tab). */\nexport const makeSelectFilteredSharedAgents = () =>\n memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentSummary[] =>\n filterUserTypeAgents(selectUserTypeAgents(agents), {\n ...consumer,\n tab: \"shared\",\n }),\n );\n\n/**\n * Factory: filters and sorts agents for a consumer. User tabs (mine / shared /\n * all) draw from user-type agents; the system tab draws from builtins.\n *\n * `includeSystemInAll` is the ADMIN reading of the \"All\" tab. For a normal\n * user, system agents are a separate catalogue and \"All\" means \"all of MY\n * agents\". For an admin surface, system agents ARE their agents — so \"All\"\n * must be a single blended list, with each row still labelled (the `system`\n * badge on `AgentRow`) so the two are never confused.\n */\nexport const makeSelectFilteredAgents = (includeSystemInAll = false) =>\n memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentSummary[] => {\n const userAgents = selectUserTypeAgents(agents);\n const builtinAgents = selectBuiltinTypeAgents(agents);\n if (consumer.tab === \"system\") {\n return filterBuiltinTypeAgents(builtinAgents, consumer);\n }\n if (includeSystemInAll && consumer.tab === \"all\") {\n return [\n ...filterUserTypeAgents(userAgents, consumer),\n ...filterBuiltinTypeAgents(builtinAgents, consumer),\n ];\n }\n return filterUserTypeAgents(userAgents, consumer);\n },\n );\n\n/** Factory: filters and sorts builtin agents for the chat agent picker. */\nexport const makeSelectFilteredBuiltinAgents = () =>\n memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentSummary[] =>\n filterBuiltinTypeAgents(selectBuiltinTypeAgents(agents), consumer),\n );\n\n// ── Card / list split (verbatim) ───────────────────────────────────────────\n\nexport interface AgentListPage {\n items: AgentSummary[];\n hasMore: boolean;\n totalAfterCards: number;\n}\n\nfunction pageAfterCards(\n filtered: AgentSummary[],\n limit: number,\n page: number,\n): AgentListPage {\n const afterCards = filtered.slice(limit);\n const pageEnd = page * AGENT_LIST_ITEMS_PER_PAGE;\n const items = afterCards.slice(0, pageEnd);\n return {\n items,\n hasMore: items.length < afterCards.length,\n totalAfterCards: afterCards.length,\n };\n}\n\n/** Factory: slices filtered owned agents into the \"cards\" hero section. */\nexport const makeSelectOwnedAgentCards = (isMobile: boolean) => {\n const selectFiltered = makeSelectFilteredOwnedAgents();\n const limit = isMobile ? AGENT_CARDS_LIMIT_MOBILE : AGENT_CARDS_LIMIT_DESKTOP;\n return memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentSummary[] => selectFiltered(agents, consumer).slice(0, limit),\n );\n};\n\n/** Factory: paginated list items for owned agents (everything after cards). */\nexport const makeSelectOwnedAgentListItems = (isMobile: boolean) => {\n const selectFiltered = makeSelectFilteredOwnedAgents();\n const limit = isMobile ? AGENT_CARDS_LIMIT_MOBILE : AGENT_CARDS_LIMIT_DESKTOP;\n return memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentListPage =>\n pageAfterCards(selectFiltered(agents, consumer), limit, consumer.listPage),\n );\n};\n\n/** Factory: slices filtered shared agents into the \"cards\" hero section. */\nexport const makeSelectSharedAgentCards = (isMobile: boolean) => {\n const selectFiltered = makeSelectFilteredSharedAgents();\n const limit = isMobile ? AGENT_CARDS_LIMIT_MOBILE : AGENT_CARDS_LIMIT_DESKTOP;\n return memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentSummary[] => selectFiltered(agents, consumer).slice(0, limit),\n );\n};\n\n/** Factory: paginated list items for shared agents (everything after cards). */\nexport const makeSelectSharedAgentListItems = (isMobile: boolean) => {\n const selectFiltered = makeSelectFilteredSharedAgents();\n const limit = isMobile ? AGENT_CARDS_LIMIT_MOBILE : AGENT_CARDS_LIMIT_DESKTOP;\n return memoize2(\n (\n agents: readonly AgentSummary[],\n consumer: AgentConsumerState,\n ): AgentListPage =>\n pageAfterCards(\n selectFiltered(agents, consumer),\n limit,\n consumer.sharedPage,\n ),\n );\n};\n\n// ── Convenience count selectors ────────────────────────────────────────────\n\n/** Factory: total count of filtered agents for a consumer. */\nexport const makeSelectFilteredAgentsCount = () => {\n const selectFiltered = makeSelectFilteredAgents();\n return memoize2(\n (agents: readonly AgentSummary[], consumer: AgentConsumerState): number =>\n selectFiltered(agents, consumer).length,\n );\n};\n\n/** Factory: total count of filtered builtin agents for a consumer. */\nexport const makeSelectFilteredBuiltinAgentsCount = () => {\n const selectFiltered = makeSelectFilteredBuiltinAgents();\n return memoize2(\n (agents: readonly AgentSummary[], consumer: AgentConsumerState): number =>\n selectFiltered(agents, consumer).length,\n );\n};\n\n// ── Consumer state convenience selectors ──────────────────────────────────\n\n/** Returns whether a consumer has any non-default filters active. */\nexport function agentConsumerHasActiveFilters(\n consumer: AgentConsumerState,\n defaults: AgentConsumerState,\n): boolean {\n return (\n consumer.tab !== defaults.tab ||\n consumer.sortBy !== defaults.sortBy ||\n consumer.searchTerm !== \"\" ||\n consumer.includedCats.length > 0 ||\n consumer.includedTags.length > 0 ||\n consumer.favFilter !== defaults.favFilter ||\n consumer.archFilter !== defaults.archFilter ||\n consumer.accessFilter !== defaults.accessFilter ||\n consumer.favoritesFirst !== defaults.favoritesFirst\n );\n}\n\n// ── Aggregate counts (for tab badges) ─────────────────────────────────────\n\n/**\n * 🚨 A BADGE COUNTS WHAT THE TAB RENDERS. Nothing else.\n *\n * Before 0.9.1 these five counted every user-type row, archived included,\n * while `filterUserTypeAgents` (archive filter `active`, the default) hid the\n * archived ones. The badge said \"Mine 416\", the list showed 412 rows and the\n * footer said \"412 agents\" — one screen, three numbers, one of them a lie\n * about agents the user cannot see or reach from there.\n *\n * `is_archived` is now honoured by the same rule the list uses, so the badge,\n * the footer and the rows agree on every tab and under every archive filter.\n *\n * 🚨 0.9.2 — AND THERE IS NO LONGER AN EXCEPTION. The system tab used to be\n * one (\"a builtin is never the user's to archive\"), which was false in the\n * database and illegal under THE ARCHIVED-ITEMS LAW. Its badge now counts\n * under the same archive rule its rows render under, so `Foundry Planner`\n * leaves the Public badge and the Public list together, or returns to both\n * together — never one without the other.\n */\nexport function agentMatchesArchiveFilter(\n agent: AgentSummary,\n archFilter: AgentArchFilter,\n): boolean {\n if (archFilter === \"active\") return !agent.isArchived;\n if (archFilter === \"archived\") return Boolean(agent.isArchived);\n return true;\n}\n\n/** Builtin rows matching an archive filter — the Public tab's badge. */\nfunction countBuiltinRows(\n agents: readonly AgentSummary[],\n archFilter: AgentArchFilter,\n): number {\n let n = 0;\n for (const a of agents) {\n if (a.agentType !== \"builtin\") continue;\n if (!agentMatchesArchiveFilter(a, archFilter)) continue;\n n += 1;\n }\n return n;\n}\n\nfunction countUserRows(\n agents: readonly AgentSummary[],\n archFilter: AgentArchFilter,\n predicate: (a: AgentSummary) => boolean,\n): number {\n let n = 0;\n for (const a of agents) {\n if (a.agentType !== \"user\") continue;\n if (!agentMatchesArchiveFilter(a, archFilter)) continue;\n if (predicate(a)) n += 1;\n }\n return n;\n}\n\nconst isOwned = (a: AgentSummary) => a.isOwner === true;\nconst isShared = (a: AgentSummary) =>\n a.isOwner === false && a.accessLevel != null;\nconst isAny = () => true;\nconst isFavorite = (a: AgentSummary) => Boolean(a.isFavorite);\n\n/**\n * The four tab badges for a consumer's CURRENT archive filter — the numbers\n * `useAgentListCore` puts on the tab strip. Flip the archive filter to\n * \"archived\" and the badges follow the list into the archive.\n */\nexport const selectAgentTabCounts = memoize2(\n (\n agents: readonly AgentSummary[],\n archFilter: AgentArchFilter,\n ): { mine: number; shared: number; all: number; system: number } => ({\n mine: countUserRows(agents, archFilter, isOwned),\n shared: countUserRows(agents, archFilter, isShared),\n all: countUserRows(agents, archFilter, isAny),\n system: countBuiltinRows(agents, archFilter),\n }),\n);\n\n/** Live user-type agents the default (`active`) list renders. */\nexport const selectTotalUserAgentsCount = memoize1(\n (agents: readonly AgentSummary[]): number =>\n countUserRows(agents, \"active\", isAny),\n);\n\nexport const selectTotalOwnedAgentsCount = memoize1(\n (agents: readonly AgentSummary[]): number =>\n countUserRows(agents, \"active\", isOwned),\n);\n\nexport const selectTotalSharedAgentsCount = memoize1(\n (agents: readonly AgentSummary[]): number =>\n countUserRows(agents, \"active\", isShared),\n);\n\n/**\n * Live builtin agents the DEFAULT (`active`) list renders — archived builtins\n * excluded, exactly like every other \"total\" beside it. Before 0.9.2 this\n * counted archived builtins too, which is how an archived `Foundry Planner`\n * reached the Public badge.\n */\nexport const selectTotalBuiltinAgentsCount = memoize1(\n (agents: readonly AgentSummary[]): number => countBuiltinRows(agents, \"active\"),\n);\n\nexport const selectTotalFavoriteAgentsCount = memoize1(\n (agents: readonly AgentSummary[]): number =>\n countUserRows(agents, \"active\", isFavorite),\n);\n"],"mappings":"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","names":["isFavorite","isRecord","isFavorite"]}