@ai-matrx/agents 0.9.1 → 0.9.2

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.
@@ -131,7 +131,25 @@ declare const SORT_OPTIONS: {
131
131
  type AgentTab = "mine" | "shared" | "all" | "system";
132
132
  /** Favorite filter. */
133
133
  type AgentFavFilter = "all" | "yes" | "no";
134
- /** Archive filter. */
134
+ /**
135
+ * The archive filter — THE ARCHIVED-ITEMS LAW's ONE control, in this
136
+ * package's existing vocabulary.
137
+ *
138
+ * > "everything should have an archive filter, and the default should always
139
+ * > hide archived, but seeing archived items should be one or two clicks
140
+ * > away." — Arman, 2026-09-09 (`common-docs/policies/archived-items.md`)
141
+ *
142
+ * Three states and no more, identical for every entity on the platform:
143
+ *
144
+ * | value | the platform's words | what the list shows |
145
+ * |------------|----------------------|--------------------------|
146
+ * | `active` | hide archived | only un-archived rows |
147
+ * | `both` | show all | every row |
148
+ * | `archived` | archived only | only archived rows |
149
+ *
150
+ * `active` is the platform default, and it is a KNOB — see
151
+ * `AgentCatalogConfig.defaults.archiveFilter`.
152
+ */
135
153
  type AgentArchFilter = "active" | "archived" | "both";
136
154
  /**
137
155
  * Access level filter.
@@ -377,6 +395,14 @@ interface AgentCatalog {
377
395
  readonly notifier: AgentCatalogNotifier | undefined;
378
396
  /** True when this catalog was given a transport and can resolve mandates. */
379
397
  readonly canResolveMandates: boolean;
398
+ /**
399
+ * The consumer state a brand-new consumer starts from, AFTER the host's
400
+ * `defaults` knob is applied. Read it instead of
401
+ * `DEFAULT_AGENT_CONSUMER_STATE` whenever the question is "is this filter at
402
+ * its default?" — a host that legitimately defaults the archive filter to
403
+ * "show all" must not have every control render as though it were modified.
404
+ */
405
+ readonly consumerDefaults: AgentConsumerState;
380
406
  getState(): AgentCatalogState;
381
407
  subscribe(listener: () => void): () => void;
382
408
  getAgent(agentId: string): AgentSummary | undefined;
@@ -515,6 +541,13 @@ interface UseAgentConsumerReturn {
515
541
  includedTags: string[];
516
542
  favFilter: AgentFavFilter;
517
543
  archFilter: AgentArchFilter;
544
+ /**
545
+ * The archive-filter state this catalog starts consumers in — the platform
546
+ * default `"active"` unless the host set the knob. What "not the default
547
+ * state" means on this surface, so the control and the footer can both say
548
+ * it honestly.
549
+ */
550
+ archFilterDefault: AgentArchFilter;
518
551
  accessFilter: AgentAccessFilter;
519
552
  favoritesFirst: boolean;
520
553
  listPage: number;
@@ -561,6 +594,12 @@ declare function useAgentConsumer(consumerId: string, options?: {
561
594
  unregisterOnUnmount?: boolean;
562
595
  /** Applied only when the consumer is first registered (idempotent). */
563
596
  initialTab?: AgentTab;
597
+ /**
598
+ * THE ARCHIVED-ITEMS LAW's per-consumer override of the catalog-wide
599
+ * `defaults.archiveFilter` knob. Applied only at first registration — the
600
+ * state belongs to the person after that.
601
+ */
602
+ initialArchFilter?: AgentArchFilter;
564
603
  }): UseAgentConsumerReturn;
565
604
 
566
605
  /**
@@ -615,6 +654,13 @@ interface AgentListCoreOptions {
615
654
  * not just at mount — so a restriction that arrives later is enforced later.
616
655
  */
617
656
  visibleTabs?: readonly AgentTab[];
657
+ /**
658
+ * THE ARCHIVED-ITEMS LAW's per-consumer override of the catalog-wide
659
+ * `defaults.archiveFilter` knob, applied once at first registration. Almost
660
+ * nothing should pass it: the platform answer is "hide archived", and the
661
+ * person reveals the archive from the control on the filter bar.
662
+ */
663
+ initialArchFilter?: AgentArchFilter;
618
664
  /** Hide records that are invalid for this call site. */
619
665
  excludeAgentIds?: readonly string[];
620
666
  /**
@@ -640,8 +686,10 @@ declare const HOVER_GRACE_MS = 900;
640
686
  * else the first allowed tab.
641
687
  */
642
688
  declare function coerceVisibleTab(current: AgentTab, allowed: readonly AgentTab[], initialTab?: AgentTab): AgentTab | null;
643
- declare function useAgentListCore({ consumerId, onSelect, navigateTo, activeAgentIdOverride, initialTab, includeSystemInAll, visibleTabs, excludeAgentIds, defaultMandateKey, }: AgentListCoreOptions): {
689
+ declare function useAgentListCore({ consumerId, onSelect, navigateTo, activeAgentIdOverride, initialTab, includeSystemInAll, visibleTabs, initialArchFilter, excludeAgentIds, defaultMandateKey, }: AgentListCoreOptions): {
644
690
  agents: AgentSummary[];
691
+ archivedHiddenCount: number;
692
+ footerLabel: string;
645
693
  isLoading: boolean;
646
694
  activeAgentId: string | null;
647
695
  pinnedAgent: AgentSummary | null;
@@ -805,8 +853,16 @@ interface AgentListContentProps {
805
853
  defaultRow?: DefaultRowState | null | undefined;
806
854
  /** When true, scroll the list to the pinned row (top). */
807
855
  listOpen?: boolean | undefined;
856
+ /**
857
+ * Rows the ARCHIVE FILTER is currently keeping off this screen — from
858
+ * `useAgentListCore`. The footer names them (clause 2 of THE ARCHIVED-ITEMS
859
+ * LAW: a screen never implies the list is everything). 0 means "nothing
860
+ * archived is hidden behind this view", which is also what a host that
861
+ * mounts this component directly and passes nothing gets.
862
+ */
863
+ archivedHiddenCount?: number | undefined;
808
864
  }
809
- declare function AgentListContent({ agents, isLoading, consumer, activeAgentId, allCategories, allTags, inputRef, onSelectAgent, resolveAgentHref, onReset, activeFilterCount, isMobile, hoveredAgent, onAgentHover, onAgentHoverEnd, onDetailPress, onFilterChipClick, rightPanel, tabCounts, visibleTabs, systemTabLabel, pinnedAgent, defaultRow, listOpen, }: AgentListContentProps): react.JSX.Element;
865
+ declare function AgentListContent({ agents, isLoading, consumer, activeAgentId, allCategories, allTags, inputRef, onSelectAgent, resolveAgentHref, onReset, activeFilterCount, isMobile, hoveredAgent, onAgentHover, onAgentHoverEnd, onDetailPress, onFilterChipClick, rightPanel, tabCounts, visibleTabs, systemTabLabel, pinnedAgent, defaultRow, listOpen, archivedHiddenCount, }: AgentListContentProps): react.JSX.Element;
810
866
 
811
867
  interface AgentFilterBarProps {
812
868
  consumer: UseAgentConsumerReturn;
@@ -823,6 +879,14 @@ interface AgentFilterBarProps {
823
879
  * fewer controls than its neighbour is the half-built shape this list exists
824
880
  * to prevent — the system tab's category/tag options simply come from the
825
881
  * builtin population (see `selectAllSystemAgentCategories`).
882
+ *
883
+ * 🚨 THE ARCHIVE CONTROL IS NOT OPTIONAL (0.9.2). It renders here, on every
884
+ * tab, for every consumer — including one whose `visibleTabs` removes the tab
885
+ * strip above it, since this bar is mounted unconditionally by
886
+ * `AgentListContent`. THE ARCHIVED-ITEMS LAW clause 3: revealing archived
887
+ * items is one or two clicks away, "on the surface itself — never zero
888
+ * (impossible) and never buried in another page". One click of this chip
889
+ * shows all; a second shows archived only; a third hides them again.
826
890
  */
827
891
  declare function AgentFilterBar({ consumer, allCategories, allTags, activeFilterCount, isMobile, rightPanel, onFilterChipClick, onReset, }: AgentFilterBarProps): react.JSX.Element;
828
892
 
@@ -897,7 +961,7 @@ declare const SearchInput: ({ ref, value, onChange, placeholder, }: {
897
961
  onChange: (v: string) => void;
898
962
  placeholder: string;
899
963
  }) => react.JSX.Element;
900
- declare function FilterChip({ icon: Icon, label, active, focused, onClick, }: {
964
+ declare function FilterChip({ icon: Icon, label, active, focused, onClick, ariaLabel, testId, }: {
901
965
  icon: ComponentType<{
902
966
  className?: string;
903
967
  }>;
@@ -905,6 +969,10 @@ declare function FilterChip({ icon: Icon, label, active, focused, onClick, }: {
905
969
  active: boolean;
906
970
  focused?: boolean;
907
971
  onClick: () => void;
972
+ /** Accessible name when the visible label alone would not say the state. */
973
+ ariaLabel?: string;
974
+ /** Stable hook so a shell test can measure the control, not a class name. */
975
+ testId?: string;
908
976
  }): react.JSX.Element;
909
977
  declare function OptionRow({ label, selected, onClick, }: {
910
978
  label: string;
@@ -131,7 +131,25 @@ declare const SORT_OPTIONS: {
131
131
  type AgentTab = "mine" | "shared" | "all" | "system";
132
132
  /** Favorite filter. */
133
133
  type AgentFavFilter = "all" | "yes" | "no";
134
- /** Archive filter. */
134
+ /**
135
+ * The archive filter — THE ARCHIVED-ITEMS LAW's ONE control, in this
136
+ * package's existing vocabulary.
137
+ *
138
+ * > "everything should have an archive filter, and the default should always
139
+ * > hide archived, but seeing archived items should be one or two clicks
140
+ * > away." — Arman, 2026-09-09 (`common-docs/policies/archived-items.md`)
141
+ *
142
+ * Three states and no more, identical for every entity on the platform:
143
+ *
144
+ * | value | the platform's words | what the list shows |
145
+ * |------------|----------------------|--------------------------|
146
+ * | `active` | hide archived | only un-archived rows |
147
+ * | `both` | show all | every row |
148
+ * | `archived` | archived only | only archived rows |
149
+ *
150
+ * `active` is the platform default, and it is a KNOB — see
151
+ * `AgentCatalogConfig.defaults.archiveFilter`.
152
+ */
135
153
  type AgentArchFilter = "active" | "archived" | "both";
136
154
  /**
137
155
  * Access level filter.
@@ -377,6 +395,14 @@ interface AgentCatalog {
377
395
  readonly notifier: AgentCatalogNotifier | undefined;
378
396
  /** True when this catalog was given a transport and can resolve mandates. */
379
397
  readonly canResolveMandates: boolean;
398
+ /**
399
+ * The consumer state a brand-new consumer starts from, AFTER the host's
400
+ * `defaults` knob is applied. Read it instead of
401
+ * `DEFAULT_AGENT_CONSUMER_STATE` whenever the question is "is this filter at
402
+ * its default?" — a host that legitimately defaults the archive filter to
403
+ * "show all" must not have every control render as though it were modified.
404
+ */
405
+ readonly consumerDefaults: AgentConsumerState;
380
406
  getState(): AgentCatalogState;
381
407
  subscribe(listener: () => void): () => void;
382
408
  getAgent(agentId: string): AgentSummary | undefined;
@@ -515,6 +541,13 @@ interface UseAgentConsumerReturn {
515
541
  includedTags: string[];
516
542
  favFilter: AgentFavFilter;
517
543
  archFilter: AgentArchFilter;
544
+ /**
545
+ * The archive-filter state this catalog starts consumers in — the platform
546
+ * default `"active"` unless the host set the knob. What "not the default
547
+ * state" means on this surface, so the control and the footer can both say
548
+ * it honestly.
549
+ */
550
+ archFilterDefault: AgentArchFilter;
518
551
  accessFilter: AgentAccessFilter;
519
552
  favoritesFirst: boolean;
520
553
  listPage: number;
@@ -561,6 +594,12 @@ declare function useAgentConsumer(consumerId: string, options?: {
561
594
  unregisterOnUnmount?: boolean;
562
595
  /** Applied only when the consumer is first registered (idempotent). */
563
596
  initialTab?: AgentTab;
597
+ /**
598
+ * THE ARCHIVED-ITEMS LAW's per-consumer override of the catalog-wide
599
+ * `defaults.archiveFilter` knob. Applied only at first registration — the
600
+ * state belongs to the person after that.
601
+ */
602
+ initialArchFilter?: AgentArchFilter;
564
603
  }): UseAgentConsumerReturn;
565
604
 
566
605
  /**
@@ -615,6 +654,13 @@ interface AgentListCoreOptions {
615
654
  * not just at mount — so a restriction that arrives later is enforced later.
616
655
  */
617
656
  visibleTabs?: readonly AgentTab[];
657
+ /**
658
+ * THE ARCHIVED-ITEMS LAW's per-consumer override of the catalog-wide
659
+ * `defaults.archiveFilter` knob, applied once at first registration. Almost
660
+ * nothing should pass it: the platform answer is "hide archived", and the
661
+ * person reveals the archive from the control on the filter bar.
662
+ */
663
+ initialArchFilter?: AgentArchFilter;
618
664
  /** Hide records that are invalid for this call site. */
619
665
  excludeAgentIds?: readonly string[];
620
666
  /**
@@ -640,8 +686,10 @@ declare const HOVER_GRACE_MS = 900;
640
686
  * else the first allowed tab.
641
687
  */
642
688
  declare function coerceVisibleTab(current: AgentTab, allowed: readonly AgentTab[], initialTab?: AgentTab): AgentTab | null;
643
- declare function useAgentListCore({ consumerId, onSelect, navigateTo, activeAgentIdOverride, initialTab, includeSystemInAll, visibleTabs, excludeAgentIds, defaultMandateKey, }: AgentListCoreOptions): {
689
+ declare function useAgentListCore({ consumerId, onSelect, navigateTo, activeAgentIdOverride, initialTab, includeSystemInAll, visibleTabs, initialArchFilter, excludeAgentIds, defaultMandateKey, }: AgentListCoreOptions): {
644
690
  agents: AgentSummary[];
691
+ archivedHiddenCount: number;
692
+ footerLabel: string;
645
693
  isLoading: boolean;
646
694
  activeAgentId: string | null;
647
695
  pinnedAgent: AgentSummary | null;
@@ -805,8 +853,16 @@ interface AgentListContentProps {
805
853
  defaultRow?: DefaultRowState | null | undefined;
806
854
  /** When true, scroll the list to the pinned row (top). */
807
855
  listOpen?: boolean | undefined;
856
+ /**
857
+ * Rows the ARCHIVE FILTER is currently keeping off this screen — from
858
+ * `useAgentListCore`. The footer names them (clause 2 of THE ARCHIVED-ITEMS
859
+ * LAW: a screen never implies the list is everything). 0 means "nothing
860
+ * archived is hidden behind this view", which is also what a host that
861
+ * mounts this component directly and passes nothing gets.
862
+ */
863
+ archivedHiddenCount?: number | undefined;
808
864
  }
809
- declare function AgentListContent({ agents, isLoading, consumer, activeAgentId, allCategories, allTags, inputRef, onSelectAgent, resolveAgentHref, onReset, activeFilterCount, isMobile, hoveredAgent, onAgentHover, onAgentHoverEnd, onDetailPress, onFilterChipClick, rightPanel, tabCounts, visibleTabs, systemTabLabel, pinnedAgent, defaultRow, listOpen, }: AgentListContentProps): react.JSX.Element;
865
+ declare function AgentListContent({ agents, isLoading, consumer, activeAgentId, allCategories, allTags, inputRef, onSelectAgent, resolveAgentHref, onReset, activeFilterCount, isMobile, hoveredAgent, onAgentHover, onAgentHoverEnd, onDetailPress, onFilterChipClick, rightPanel, tabCounts, visibleTabs, systemTabLabel, pinnedAgent, defaultRow, listOpen, archivedHiddenCount, }: AgentListContentProps): react.JSX.Element;
810
866
 
811
867
  interface AgentFilterBarProps {
812
868
  consumer: UseAgentConsumerReturn;
@@ -823,6 +879,14 @@ interface AgentFilterBarProps {
823
879
  * fewer controls than its neighbour is the half-built shape this list exists
824
880
  * to prevent — the system tab's category/tag options simply come from the
825
881
  * builtin population (see `selectAllSystemAgentCategories`).
882
+ *
883
+ * 🚨 THE ARCHIVE CONTROL IS NOT OPTIONAL (0.9.2). It renders here, on every
884
+ * tab, for every consumer — including one whose `visibleTabs` removes the tab
885
+ * strip above it, since this bar is mounted unconditionally by
886
+ * `AgentListContent`. THE ARCHIVED-ITEMS LAW clause 3: revealing archived
887
+ * items is one or two clicks away, "on the surface itself — never zero
888
+ * (impossible) and never buried in another page". One click of this chip
889
+ * shows all; a second shows archived only; a third hides them again.
826
890
  */
827
891
  declare function AgentFilterBar({ consumer, allCategories, allTags, activeFilterCount, isMobile, rightPanel, onFilterChipClick, onReset, }: AgentFilterBarProps): react.JSX.Element;
828
892
 
@@ -897,7 +961,7 @@ declare const SearchInput: ({ ref, value, onChange, placeholder, }: {
897
961
  onChange: (v: string) => void;
898
962
  placeholder: string;
899
963
  }) => react.JSX.Element;
900
- declare function FilterChip({ icon: Icon, label, active, focused, onClick, }: {
964
+ declare function FilterChip({ icon: Icon, label, active, focused, onClick, ariaLabel, testId, }: {
901
965
  icon: ComponentType<{
902
966
  className?: string;
903
967
  }>;
@@ -905,6 +969,10 @@ declare function FilterChip({ icon: Icon, label, active, focused, onClick, }: {
905
969
  active: boolean;
906
970
  focused?: boolean;
907
971
  onClick: () => void;
972
+ /** Accessible name when the visible label alone would not say the state. */
973
+ ariaLabel?: string;
974
+ /** Stable hook so a shell test can measure the control, not a class name. */
975
+ testId?: string;
908
976
  }): react.JSX.Element;
909
977
  declare function OptionRow({ label, selected, onClick, }: {
910
978
  label: string;
@@ -117,53 +117,27 @@ function AgentCatalogProvider({
117
117
 
118
118
  // catalog/shared/useAgentConsumer.ts
119
119
  import { useCallback as useCallback2, useEffect, useRef, useState } from "react";
120
-
121
- // catalog/types.ts
122
- function isMandateAgentId(id) {
123
- return id.startsWith("mandate:");
124
- }
125
- var SORT_OPTIONS = [
126
- { value: "updated-desc", label: "Recent" },
127
- { value: "created-desc", label: "Created" },
128
- { value: "name-asc", label: "A \u2192 Z" },
129
- { value: "name-desc", label: "Z \u2192 A" },
130
- { value: "category-asc", label: "Category" }
131
- ];
132
- var AGENT_NONE_SENTINEL = "__none__";
133
- var DEFAULT_AGENT_CONSUMER_STATE = {
134
- tab: "mine",
135
- sortBy: "updated-desc",
136
- searchTerm: "",
137
- includedCats: [],
138
- includedTags: [],
139
- favFilter: "all",
140
- archFilter: "active",
141
- accessFilter: "any",
142
- favoritesFirst: true,
143
- listPage: 1,
144
- sharedPage: 1,
145
- serverMatchedIds: [],
146
- isServerSearching: false,
147
- deepSearch: false
148
- };
149
-
150
- // catalog/shared/useAgentConsumer.ts
151
120
  var DEBOUNCE_MS = 250;
152
121
  var MIN_QUERY_LENGTH = 2;
153
122
  function useAgentConsumer(consumerId, options) {
154
123
  const catalog = useAgentCatalog();
124
+ const defaults = catalog.consumerDefaults;
155
125
  const selectConsumer = useCallback2(
156
- (state) => state.consumers[consumerId] ?? DEFAULT_AGENT_CONSUMER_STATE,
157
- [consumerId]
126
+ (state) => state.consumers[consumerId] ?? defaults,
127
+ [consumerId, defaults]
158
128
  );
159
129
  const consumer = useAgentCatalogState(selectConsumer);
160
130
  const optionsRef = useRef(options);
161
131
  optionsRef.current = options;
162
132
  useEffect(() => {
163
133
  const opts = optionsRef.current;
134
+ const initial = {
135
+ ...opts?.initialTab ? { tab: opts.initialTab } : {},
136
+ ...opts?.initialArchFilter ? { archFilter: opts.initialArchFilter } : {}
137
+ };
164
138
  catalog.registerConsumer(
165
139
  consumerId,
166
- opts?.initialTab ? { tab: opts.initialTab } : void 0
140
+ Object.keys(initial).length > 0 ? initial : void 0
167
141
  );
168
142
  return () => {
169
143
  if (optionsRef.current?.unregisterOnUnmount) {
@@ -286,7 +260,10 @@ function useAgentConsumer(consumerId, options) {
286
260
  isSearching
287
261
  });
288
262
  }, [consumerId, catalog, matchedIds, isSearching]);
289
- const hasActiveFilters = consumer.searchTerm !== "" || consumer.includedCats.length > 0 || consumer.includedTags.length > 0 || consumer.favFilter !== "all" || consumer.archFilter !== "active" || consumer.accessFilter !== "any" || !consumer.favoritesFirst;
263
+ const hasActiveFilters = consumer.searchTerm !== "" || consumer.includedCats.length > 0 || consumer.includedTags.length > 0 || consumer.favFilter !== "all" || // The archive filter is compared to THIS CATALOG'S default, not to the
264
+ // hardcoded platform one: a host that legitimately defaults to "show all"
265
+ // must not have the reset control permanently lit.
266
+ consumer.archFilter !== defaults.archFilter || consumer.accessFilter !== "any" || !consumer.favoritesFirst;
290
267
  return {
291
268
  tab: consumer.tab,
292
269
  sortBy: consumer.sortBy,
@@ -295,6 +272,7 @@ function useAgentConsumer(consumerId, options) {
295
272
  includedTags: consumer.includedTags,
296
273
  favFilter: consumer.favFilter,
297
274
  archFilter: consumer.archFilter,
275
+ archFilterDefault: defaults.archFilter,
298
276
  accessFilter: consumer.accessFilter,
299
277
  favoritesFirst: consumer.favoritesFirst,
300
278
  listPage: consumer.listPage,
@@ -330,6 +308,34 @@ import {
330
308
  useState as useState2
331
309
  } from "react";
332
310
 
311
+ // catalog/types.ts
312
+ function isMandateAgentId(id) {
313
+ return id.startsWith("mandate:");
314
+ }
315
+ var SORT_OPTIONS = [
316
+ { value: "updated-desc", label: "Recent" },
317
+ { value: "created-desc", label: "Created" },
318
+ { value: "name-asc", label: "A \u2192 Z" },
319
+ { value: "name-desc", label: "Z \u2192 A" },
320
+ { value: "category-asc", label: "Category" }
321
+ ];
322
+ var ARCHIVE_FILTER_ORDER = [
323
+ "active",
324
+ "both",
325
+ "archived"
326
+ ];
327
+ var ARCHIVE_FILTER_OPTIONS = [
328
+ { value: "active", label: "Hide archived", chip: "Archive" },
329
+ { value: "both", label: "Show all", chip: "All + archived" },
330
+ { value: "archived", label: "Archived only", chip: "Archived only" }
331
+ ];
332
+ function nextArchFilter(current) {
333
+ const index = ARCHIVE_FILTER_ORDER.indexOf(current);
334
+ if (index < 0) return ARCHIVE_FILTER_ORDER[0];
335
+ return ARCHIVE_FILTER_ORDER[(index + 1) % ARCHIVE_FILTER_ORDER.length];
336
+ }
337
+ var AGENT_NONE_SENTINEL = "__none__";
338
+
333
339
  // catalog/labels.ts
334
340
  function agentListEmptyLabel(tab, labels) {
335
341
  switch (tab) {
@@ -346,6 +352,26 @@ function shouldDefaultAgentListToPublicTab(args) {
346
352
  if (!args.agentsLoaded) return false;
347
353
  return args.ownedCount === 0;
348
354
  }
355
+ function agentArchiveFilterChipLabel(archFilter) {
356
+ return ARCHIVE_FILTER_OPTIONS.find((o) => o.value === archFilter)?.chip ?? "Archive";
357
+ }
358
+ function agentArchiveFilterStateLabel(archFilter) {
359
+ return ARCHIVE_FILTER_OPTIONS.find((o) => o.value === archFilter)?.label ?? "Hide archived";
360
+ }
361
+ function agentArchiveFilterControlLabel(archFilter) {
362
+ return `Archive filter: ${agentArchiveFilterStateLabel(
363
+ archFilter
364
+ ).toLowerCase()}. Click for ${agentArchiveFilterStateLabel(
365
+ nextArchFilter(archFilter)
366
+ ).toLowerCase()}`;
367
+ }
368
+ function agentListFooterLabel(args) {
369
+ const { count, archFilter, archivedHiddenCount } = args;
370
+ if (archFilter === "archived") return `${count} archived shown`;
371
+ const base = `${count} agent${count !== 1 ? "s" : ""}`;
372
+ if (archFilter === "both") return `${base} \xB7 archived shown`;
373
+ return archivedHiddenCount > 0 ? `${base} \xB7 ${archivedHiddenCount} archived hidden` : base;
374
+ }
349
375
 
350
376
  // catalog/score.ts
351
377
  function computeAgentSearchScore(agent, query) {
@@ -536,8 +562,7 @@ function filterUserTypeAgents(agents, consumer) {
536
562
  if (tab === "mine" && agent.isOwner !== true) return false;
537
563
  if (tab === "shared" && !(agent.isOwner === false && agent.accessLevel != null))
538
564
  return false;
539
- if (archFilter === "active" && agent.isArchived) return false;
540
- if (archFilter === "archived" && !agent.isArchived) return false;
565
+ if (!agentMatchesArchiveFilter(agent, archFilter)) return false;
541
566
  if (favFilter === "yes" && !agent.isFavorite) return false;
542
567
  if (favFilter === "no" && agent.isFavorite) return false;
543
568
  if (accessFilter === "owned" && agent.isOwner !== true) return false;
@@ -567,9 +592,10 @@ function filterUserTypeAgents(agents, consumer) {
567
592
  return sortFilteredAgents(filtered, consumer);
568
593
  }
569
594
  function filterBuiltinTypeAgents(agents, consumer) {
570
- const { searchTerm, favFilter, includedCats, includedTags } = consumer;
595
+ const { searchTerm, favFilter, archFilter, includedCats, includedTags } = consumer;
571
596
  const serverMatched = new Set(consumer.serverMatchedIds);
572
597
  const filtered = agents.filter((agent) => {
598
+ if (!agentMatchesArchiveFilter(agent, archFilter)) return false;
573
599
  if (favFilter === "yes" && !agent.isFavorite) return false;
574
600
  if (favFilter === "no" && agent.isFavorite) return false;
575
601
  if (includedCats.length > 0) {
@@ -615,6 +641,15 @@ function agentMatchesArchiveFilter(agent, archFilter) {
615
641
  if (archFilter === "archived") return Boolean(agent.isArchived);
616
642
  return true;
617
643
  }
644
+ function countBuiltinRows(agents, archFilter) {
645
+ let n = 0;
646
+ for (const a of agents) {
647
+ if (a.agentType !== "builtin") continue;
648
+ if (!agentMatchesArchiveFilter(a, archFilter)) continue;
649
+ n += 1;
650
+ }
651
+ return n;
652
+ }
618
653
  function countUserRows(agents, archFilter, predicate) {
619
654
  let n = 0;
620
655
  for (const a of agents) {
@@ -633,7 +668,7 @@ var selectAgentTabCounts = memoize2(
633
668
  mine: countUserRows(agents, archFilter, isOwned),
634
669
  shared: countUserRows(agents, archFilter, isShared),
635
670
  all: countUserRows(agents, archFilter, isAny),
636
- system: selectBuiltinTypeAgents(agents).length
671
+ system: countBuiltinRows(agents, archFilter)
637
672
  })
638
673
  );
639
674
  var selectTotalUserAgentsCount = memoize1(
@@ -646,7 +681,7 @@ var selectTotalSharedAgentsCount = memoize1(
646
681
  (agents) => countUserRows(agents, "active", isShared)
647
682
  );
648
683
  var selectTotalBuiltinAgentsCount = memoize1(
649
- (agents) => selectBuiltinTypeAgents(agents).length
684
+ (agents) => countBuiltinRows(agents, "active")
650
685
  );
651
686
  var selectTotalFavoriteAgentsCount = memoize1(
652
687
  (agents) => countUserRows(agents, "active", isFavorite)
@@ -668,6 +703,7 @@ function useAgentListCore({
668
703
  initialTab,
669
704
  includeSystemInAll = false,
670
705
  visibleTabs,
706
+ initialArchFilter,
671
707
  excludeAgentIds = EMPTY_EXCLUDES,
672
708
  defaultMandateKey
673
709
  }) {
@@ -677,7 +713,10 @@ function useAgentListCore({
677
713
  const [hoveredAgent, setHoveredAgent] = useState2(null);
678
714
  const hoverLeaveTimerRef = useRef2(null);
679
715
  const defaultTabAppliedRef = useRef2(false);
680
- const consumer = useAgentConsumer(consumerId, { unregisterOnUnmount: true });
716
+ const consumer = useAgentConsumer(consumerId, {
717
+ unregisterOnUnmount: true,
718
+ ...initialArchFilter ? { initialArchFilter } : {}
719
+ });
681
720
  const rows = useAgentCatalogRows();
682
721
  const userId = catalog.getUserIdOrNull();
683
722
  const tabCountsForFilter = selectAgentTabCounts(rows, consumer.state.archFilter);
@@ -691,7 +730,20 @@ function useAgentListCore({
691
730
  () => new Set(excludeAgentIds),
692
731
  [excludeAgentIds]
693
732
  );
694
- const agents = excludedAgentIds.size === 0 ? filteredAgents : filteredAgents.filter((agent) => !excludedAgentIds.has(agent.id));
733
+ const applyExcludes = useCallback3(
734
+ (list) => excludedAgentIds.size === 0 ? list : list.filter((agent) => !excludedAgentIds.has(agent.id)),
735
+ [excludedAgentIds]
736
+ );
737
+ const agents = applyExcludes(filteredAgents);
738
+ const selectArchivedProbe = useMemo3(
739
+ () => makeSelectFilteredAgents(includeSystemInAll),
740
+ [includeSystemInAll]
741
+ );
742
+ const archiveProbeState = useMemo3(
743
+ () => ({ ...consumer.state, archFilter: "archived" }),
744
+ [consumer.state]
745
+ );
746
+ const archivedHiddenCount = consumer.archFilter === "active" ? applyExcludes(selectArchivedProbe(rows, archiveProbeState)).length : 0;
695
747
  const status = useAgentCatalogState(selectStatus);
696
748
  const activeAgentId = activeAgentIdOverride ?? null;
697
749
  const pinnedAgent = activeAgentId ? catalog.getAgent(activeAgentId) : void 0;
@@ -778,7 +830,9 @@ function useAgentListCore({
778
830
  },
779
831
  [onSelect, navigateTo, navigate, catalog, consumerId]
780
832
  );
781
- const activeFilterCount = (consumer.sortBy !== "updated-desc" ? 1 : 0) + (consumer.includedCats.length > 0 ? 1 : 0) + (consumer.includedTags.length > 0 ? 1 : 0) + (consumer.favFilter !== "all" ? 1 : 0);
833
+ const activeFilterCount = (consumer.sortBy !== "updated-desc" ? 1 : 0) + (consumer.includedCats.length > 0 ? 1 : 0) + (consumer.includedTags.length > 0 ? 1 : 0) + (consumer.favFilter !== "all" ? 1 : 0) + // The archive filter counts like every other filter, so a list showing
834
+ // archived rows offers the reset control that puts them away again.
835
+ (consumer.archFilter !== consumer.archFilterDefault ? 1 : 0);
782
836
  const handleAgentHover = useCallback3(
783
837
  (agent, panelOpen) => {
784
838
  if (panelOpen) return;
@@ -819,8 +873,15 @@ function useAgentListCore({
819
873
  },
820
874
  []
821
875
  );
876
+ const footerLabel = agentListFooterLabel({
877
+ count: agents.length,
878
+ archFilter: consumer.archFilter,
879
+ archivedHiddenCount
880
+ });
822
881
  return {
823
882
  agents,
883
+ archivedHiddenCount,
884
+ footerLabel,
824
885
  isLoading,
825
886
  activeAgentId,
826
887
  pinnedAgent: pinnedAgent ?? null,
@@ -950,6 +1011,18 @@ var SHAPES = {
950
1011
  "M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"
951
1012
  ]
952
1013
  },
1014
+ /**
1015
+ * THE ARCHIVE GLYPH (Lucide `archive`) — the ONE mark of the platform
1016
+ * archive filter, drawn identically in every Matrx client so the control a
1017
+ * person learns on one surface is recognisable on all of them.
1018
+ */
1019
+ archive: {
1020
+ paths: [
1021
+ "M3 3h18a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z",
1022
+ "M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8",
1023
+ "M10 12h4"
1024
+ ]
1025
+ },
953
1026
  circleCheck: {
954
1027
  paths: ["m9 12 2 2 4-4"],
955
1028
  circles: [{ cx: 12, cy: 12, r: 10 }]
@@ -1020,6 +1093,7 @@ var ArrowUpDownIcon = makeIcon("arrowUpDown");
1020
1093
  var FolderIcon = makeIcon("folder");
1021
1094
  var TagIcon = makeIcon("tag");
1022
1095
  var RotateCcwIcon = makeIcon("rotateCcw");
1096
+ var ArchiveIcon = makeIcon("archive");
1023
1097
  var LoaderIcon = makeIcon("loader");
1024
1098
  var UsersIcon = makeIcon("users");
1025
1099
  var ClockIcon = makeIcon("clock");
@@ -1077,13 +1151,17 @@ function FilterChip({
1077
1151
  label,
1078
1152
  active,
1079
1153
  focused,
1080
- onClick
1154
+ onClick,
1155
+ ariaLabel,
1156
+ testId
1081
1157
  }) {
1082
1158
  return /* @__PURE__ */ jsxs2(
1083
1159
  "button",
1084
1160
  {
1085
1161
  type: "button",
1086
1162
  onClick,
1163
+ ...ariaLabel ? { "aria-label": ariaLabel } : {},
1164
+ ...testId ? { "data-testid": testId } : {},
1087
1165
  className: cn(
1088
1166
  "inline-flex items-center gap-1 h-6 px-1.5 rounded text-[11px] font-medium shrink-0 transition-colors",
1089
1167
  focused ? "bg-primary/15 text-primary border border-primary/30 ring-1 ring-primary/20" : active ? "bg-primary/10 text-primary border border-primary/20" : "text-muted-foreground hover:text-foreground hover:bg-muted/50 border border-transparent"
@@ -1506,6 +1584,17 @@ function AgentFilterBar({
1506
1584
  }
1507
1585
  }
1508
1586
  ),
1587
+ /* @__PURE__ */ jsx8(
1588
+ FilterChip,
1589
+ {
1590
+ icon: ArchiveIcon,
1591
+ label: agentArchiveFilterChipLabel(consumer.archFilter),
1592
+ active: consumer.archFilter !== consumer.archFilterDefault,
1593
+ ariaLabel: agentArchiveFilterControlLabel(consumer.archFilter),
1594
+ testId: "agent-archive-filter",
1595
+ onClick: () => consumer.setArchFilter(nextArchFilter(consumer.archFilter))
1596
+ }
1597
+ ),
1509
1598
  allCategories.length > 0 && /* @__PURE__ */ jsx8(
1510
1599
  FilterChip,
1511
1600
  {
@@ -1705,7 +1794,8 @@ function AgentListContent({
1705
1794
  systemTabLabel,
1706
1795
  pinnedAgent = null,
1707
1796
  defaultRow = null,
1708
- listOpen = false
1797
+ listOpen = false,
1798
+ archivedHiddenCount = 0
1709
1799
  }) {
1710
1800
  const catalog = useAgentCatalog();
1711
1801
  const listScrollRef = useRef3(null);
@@ -1843,11 +1933,18 @@ function AgentListContent({
1843
1933
  ] }) }),
1844
1934
  /* @__PURE__ */ jsx11("div", { className: "h-px bg-border shrink-0" }),
1845
1935
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between px-2.5 py-1.5 shrink-0", children: [
1846
- /* @__PURE__ */ jsxs8("span", { className: "text-[10px] text-muted-foreground tabular-nums", children: [
1847
- agents.length,
1848
- " agent",
1849
- agents.length !== 1 ? "s" : ""
1850
- ] }),
1936
+ /* @__PURE__ */ jsx11(
1937
+ "span",
1938
+ {
1939
+ "data-testid": "agent-list-footer",
1940
+ className: "text-[10px] text-muted-foreground tabular-nums",
1941
+ children: agentListFooterLabel({
1942
+ count: agents.length,
1943
+ archFilter: consumer.archFilter,
1944
+ archivedHiddenCount
1945
+ })
1946
+ }
1947
+ ),
1851
1948
  consumer.searchTerm && /* @__PURE__ */ jsx11(
1852
1949
  "button",
1853
1950
  {
@@ -2070,6 +2167,7 @@ function AgentListDropdown({
2070
2167
  const inputRef = useRef4(null);
2071
2168
  const {
2072
2169
  agents,
2170
+ archivedHiddenCount,
2073
2171
  isLoading,
2074
2172
  activeAgentId,
2075
2173
  pinnedAgent,
@@ -2205,6 +2303,7 @@ function AgentListDropdown({
2205
2303
  onFilterChipClick: handleFilterChipClick,
2206
2304
  rightPanel,
2207
2305
  tabCounts,
2306
+ archivedHiddenCount,
2208
2307
  ...visibleTabs ? { visibleTabs } : {},
2209
2308
  ...systemTabLabel ?? (includeSystemInAll ? "System" : void 0) ? {
2210
2309
  systemTabLabel: systemTabLabel ?? (includeSystemInAll ? "System" : void 0)
@@ -2361,6 +2460,7 @@ function AgentListInlinePicker({
2361
2460
  const [mobileSubView, setMobileSubView] = useState4(null);
2362
2461
  const {
2363
2462
  agents,
2463
+ archivedHiddenCount,
2364
2464
  isLoading,
2365
2465
  allCategories,
2366
2466
  allTags,
@@ -2467,6 +2567,7 @@ function AgentListInlinePicker({
2467
2567
  onFilterChipClick: handleFilterChipClick,
2468
2568
  rightPanel: null,
2469
2569
  tabCounts,
2570
+ archivedHiddenCount,
2470
2571
  ...visibleTabs ? { visibleTabs } : {},
2471
2572
  ...systemTabLabel ?? (includeSystemInAll ? "System" : void 0) ? {
2472
2573
  systemTabLabel: systemTabLabel ?? (includeSystemInAll ? "System" : void 0)