@burdenoff/microfe-subscriberbot 2026.1023.1 → 2026.1029.1

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 (46) hide show
  1. package/dist/subscriberbot/admin/AdminDashboardPage.js +5 -5
  2. package/dist/subscriberbot/admin/AdminDashboardPage.js.map +1 -1
  3. package/dist/subscriberbot/components/PostureOptions.d.ts +10 -0
  4. package/dist/subscriberbot/components/PostureOptions.d.ts.map +1 -0
  5. package/dist/subscriberbot/components/PostureOptions.js +20 -0
  6. package/dist/subscriberbot/components/PostureOptions.js.map +1 -0
  7. package/dist/subscriberbot/components/index.d.ts +2 -0
  8. package/dist/subscriberbot/components/index.d.ts.map +1 -1
  9. package/dist/subscriberbot/components/index.js +1 -0
  10. package/dist/subscriberbot/hooks/index.d.ts +1 -0
  11. package/dist/subscriberbot/hooks/index.d.ts.map +1 -1
  12. package/dist/subscriberbot/hooks/index.js +2 -1
  13. package/dist/subscriberbot/hooks/useAutonomousAgentMode.d.ts +15 -0
  14. package/dist/subscriberbot/hooks/useAutonomousAgentMode.d.ts.map +1 -0
  15. package/dist/subscriberbot/hooks/useAutonomousAgentMode.js +13 -0
  16. package/dist/subscriberbot/hooks/useAutonomousAgentMode.js.map +1 -0
  17. package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts.map +1 -1
  18. package/dist/subscriberbot/hooks/useSubscriberBotApi.js +9 -0
  19. package/dist/subscriberbot/hooks/useSubscriberBotApi.js.map +1 -1
  20. package/dist/subscriberbot/pages/AssetVaultPage.js +16 -16
  21. package/dist/subscriberbot/pages/DashboardPage.js +23 -23
  22. package/dist/subscriberbot/pages/DashboardPage.js.map +1 -1
  23. package/dist/subscriberbot/pages/InboxPage.js +62 -62
  24. package/dist/subscriberbot/pages/InsightsPage.js +14 -14
  25. package/dist/subscriberbot/pages/InvoicesPage.js +66 -66
  26. package/dist/subscriberbot/pages/WorkflowsPage.js +20 -20
  27. package/dist/subscriberbot/pages/agents/AgentDetailPage.d.ts.map +1 -1
  28. package/dist/subscriberbot/pages/agents/AgentDetailPage.js +184 -182
  29. package/dist/subscriberbot/pages/agents/AgentDetailPage.js.map +1 -1
  30. package/dist/subscriberbot/pages/agents/AgentNewPage.d.ts.map +1 -1
  31. package/dist/subscriberbot/pages/agents/AgentNewPage.js +77 -79
  32. package/dist/subscriberbot/pages/agents/AgentNewPage.js.map +1 -1
  33. package/dist/subscriberbot/pages/agents/AgentsListPage.d.ts.map +1 -1
  34. package/dist/subscriberbot/pages/agents/AgentsListPage.js +134 -133
  35. package/dist/subscriberbot/pages/agents/AgentsListPage.js.map +1 -1
  36. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js +64 -64
  37. package/dist/subscriberbot/pages/providers/ProviderNewPage.js +3 -3
  38. package/dist/subscriberbot/pages/providers/ProvidersListPage.js +18 -18
  39. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.d.ts.map +1 -1
  40. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js +122 -89
  41. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -1
  42. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js +6 -6
  43. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js +7 -7
  44. package/dist/subscriberbot/types/index.d.ts +1 -0
  45. package/dist/subscriberbot/types/index.d.ts.map +1 -1
  46. package/package.json +1 -1
@@ -4,17 +4,18 @@ import { MetricsCard as n } from "../../components/MetricsCard.js";
4
4
  import { formatEnumLabel as r, formatRelativeTime as i } from "../../utils/formatters.js";
5
5
  import { StatusBadge as a } from "../../components/StatusBadge.js";
6
6
  import { EmptyState as o } from "../../components/EmptyState.js";
7
- import { ErrorView as s, LoadingView as c } from "../../components/StateViews.js";
8
- import { Donut as l, Legend as u } from "../../components/viz.js";
7
+ import { useTr as s } from "../../hooks/useTr.js";
8
+ import { PostureOptions as c } from "../../components/PostureOptions.js";
9
+ import { ErrorView as l, LoadingView as u } from "../../components/StateViews.js";
10
+ import { Donut as d, Legend as f } from "../../components/viz.js";
9
11
  import "../../components/index.js";
10
- import { useAgents as d, useSetAgentStatus as f } from "../../hooks/useSubscriberBotApi.js";
11
- import { useTr as p } from "../../hooks/useTr.js";
12
- import { useState as m } from "react";
13
- import { ArrowLeftRight as h, Bot as g, Building2 as _, Clock as v, ConciergeBell as y, DollarSign as b, Handshake as x, Mail as S, Plus as C, RefreshCw as w, Search as T, ShieldCheck as E, Sparkles as D, Zap as O } from "lucide-react";
14
- import { Fragment as k, jsx as A, jsxs as j } from "react/jsx-runtime";
15
- import { GlassCard as M, PagePurpose as N } from "@burdenoff/fe-libs/ui";
12
+ import { useAgents as p, useSetAgentStatus as m } from "../../hooks/useSubscriberBotApi.js";
13
+ import { useState as h } from "react";
14
+ import { ArrowLeftRight as g, Bot as _, Building2 as v, Clock as y, ConciergeBell as b, DollarSign as x, Handshake as S, Mail as C, Plus as w, RefreshCw as T, Search as E, ShieldCheck as D, Sparkles as O, Zap as k } from "lucide-react";
15
+ import { Fragment as A, jsx as j, jsxs as M } from "react/jsx-runtime";
16
+ import { GlassCard as N, PagePurpose as P } from "@burdenoff/fe-libs/ui";
16
17
  //#region src/subscriberbot/pages/agents/AgentsListPage.tsx
17
- var P = {
18
+ var F = {
18
19
  DISCOVERY: "agents.kinds.discovery",
19
20
  RENEWAL: "agents.kinds.renewal",
20
21
  COST: "agents.kinds.cost",
@@ -24,222 +25,222 @@ var P = {
24
25
  NEGOTIATION: "agents.kinds.negotiation",
25
26
  MIGRATION: "agents.kinds.migration",
26
27
  CONCIERGE: "agents.kinds.concierge"
27
- }, F = [
28
+ }, I = [
28
29
  "DISABLED",
29
30
  "SUGGEST_ONLY",
30
31
  "AUTONOMOUS"
31
- ], I = {
32
- DISCOVERY: T,
33
- RENEWAL: w,
34
- COST: b,
35
- NEWSLETTER: S,
36
- VENDOR: _,
37
- COMPLIANCE: E,
38
- NEGOTIATION: x,
39
- MIGRATION: h,
40
- CONCIERGE: y
41
- }, L = {
32
+ ], L = {
33
+ DISCOVERY: E,
34
+ RENEWAL: T,
35
+ COST: x,
36
+ NEWSLETTER: C,
37
+ VENDOR: v,
38
+ COMPLIANCE: D,
39
+ NEGOTIATION: S,
40
+ MIGRATION: g,
41
+ CONCIERGE: b
42
+ }, R = {
42
43
  AUTONOMOUS: "var(--color-status-success-text)",
43
44
  SUGGEST_ONLY: "var(--color-accent-indigo)",
44
45
  DISABLED: "var(--color-text-secondary)"
45
- }, R = 1440 * 60 * 1e3;
46
- function z() {
47
- let h = p(), { navigateTo: _ } = e(), [y, b] = m(""), [x, S] = m(""), w = [{
46
+ }, z = 1440 * 60 * 1e3;
47
+ function B() {
48
+ let g = s(), { navigateTo: v } = e(), [b, x] = h(""), [S, C] = h(""), T = [{
48
49
  value: "",
49
- label: h("agents.filters.allKinds", "All kinds")
50
- }, ...Object.entries(P).map(([e, t]) => ({
50
+ label: g("agents.filters.allKinds", "All kinds")
51
+ }, ...Object.entries(F).map(([e, t]) => ({
51
52
  value: e,
52
- label: h(t, r(e))
53
- }))], { data: T, isLoading: E, isError: z, refetch: B } = d({
54
- kind: y || void 0,
55
- status: x || void 0
56
- }), V = f(), H = T ?? [], U = {
53
+ label: g(t, r(e))
54
+ }))], { data: E, isLoading: D, isError: B, refetch: V } = p({
55
+ kind: b || void 0,
56
+ status: S || void 0
57
+ }), H = m(), U = E ?? [], W = {
57
58
  AUTONOMOUS: 0,
58
59
  SUGGEST_ONLY: 0,
59
60
  DISABLED: 0
60
- }, W = 0, G = Date.now();
61
- for (let e of H) U[e.status] += 1, e.lastRunAt && G - new Date(e.lastRunAt).getTime() <= 7 * R && (W += 1);
62
- let K = F.map((e) => ({
63
- label: h(`agents.postures.${e.toLowerCase()}`, r(e)),
64
- value: U[e],
65
- color: L[e]
61
+ }, G = 0, K = Date.now();
62
+ for (let e of U) W[e.status] += 1, e.lastRunAt && K - new Date(e.lastRunAt).getTime() <= 7 * z && (G += 1);
63
+ let q = I.map((e) => ({
64
+ label: g(`agents.postures.${e.toLowerCase()}`, r(e)),
65
+ value: W[e],
66
+ color: R[e]
66
67
  })).filter((e) => e.value > 0);
67
- return /* @__PURE__ */ j(t, {
68
- title: h("agents.title", "AI Agents"),
69
- description: h("agents.description", "Specialized agents that automate your recurring portfolio"),
70
- actions: /* @__PURE__ */ j("button", {
68
+ return /* @__PURE__ */ M(t, {
69
+ title: g("agents.title", "AI Agents"),
70
+ description: g("agents.description", "Specialized agents that automate your recurring portfolio"),
71
+ actions: /* @__PURE__ */ M("button", {
71
72
  type: "button",
72
- onClick: () => _("/agents/new"),
73
+ onClick: () => v("/agents/new"),
73
74
  className: "inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90",
74
75
  children: [
75
- /* @__PURE__ */ A(C, { className: "h-4 w-4" }),
76
+ /* @__PURE__ */ j(w, { className: "h-4 w-4" }),
76
77
  " ",
77
- h("agents.newAgent", "New agent")
78
+ g("agents.newAgent", "New agent")
78
79
  ]
79
80
  }),
80
81
  children: [
81
- /* @__PURE__ */ A(N, {
82
+ /* @__PURE__ */ j(P, {
82
83
  className: "mb-4",
83
- children: h("agents.purpose", "Agents propose; your policies decide what they may do autonomously. Set each agent's posture — Disabled, Suggest-only, or Autonomous — and open one to review its policies.")
84
+ children: g("agents.purpose", "Agents propose; your policies decide what they may do autonomously. Set each agent's posture — Disabled, Suggest-only, or Autonomous — and open one to review its policies.")
84
85
  }),
85
- /* @__PURE__ */ j("div", {
86
+ /* @__PURE__ */ M("div", {
86
87
  className: "flex flex-wrap items-center gap-3",
87
- children: [/* @__PURE__ */ A("select", {
88
- "aria-label": h("agents.filters.kindLabel", "Filter by kind"),
89
- value: y,
90
- onChange: (e) => b(e.target.value),
88
+ children: [/* @__PURE__ */ j("select", {
89
+ "aria-label": g("agents.filters.kindLabel", "Filter by kind"),
90
+ value: b,
91
+ onChange: (e) => x(e.target.value),
91
92
  className: "rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
92
- children: w.map((e) => /* @__PURE__ */ A("option", {
93
+ children: T.map((e) => /* @__PURE__ */ j("option", {
93
94
  value: e.value,
94
95
  children: e.label
95
96
  }, e.value))
96
- }), /* @__PURE__ */ j("select", {
97
- "aria-label": h("agents.filters.postureLabel", "Filter by posture"),
98
- value: x,
99
- onChange: (e) => S(e.target.value),
97
+ }), /* @__PURE__ */ M("select", {
98
+ "aria-label": g("agents.filters.postureLabel", "Filter by posture"),
99
+ value: S,
100
+ onChange: (e) => C(e.target.value),
100
101
  className: "rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
101
- children: [/* @__PURE__ */ A("option", {
102
+ children: [/* @__PURE__ */ j("option", {
102
103
  value: "",
103
- children: h("agents.filters.anyPosture", "Any posture")
104
- }), F.map((e) => /* @__PURE__ */ A("option", {
104
+ children: g("agents.filters.anyPosture", "Any posture")
105
+ }), I.map((e) => /* @__PURE__ */ j("option", {
105
106
  value: e,
106
- children: h(`agents.postures.${e.toLowerCase()}`, r(e))
107
+ children: g(`agents.postures.${e.toLowerCase()}`, r(e))
107
108
  }, e))]
108
109
  })]
109
110
  }),
110
- E ? /* @__PURE__ */ A(c, { label: h("agents.loading", "Loading agents…") }) : z ? /* @__PURE__ */ A(s, {
111
- message: h("agents.error", "Could not load agents."),
112
- onRetry: () => void B()
113
- }) : H.length === 0 ? /* @__PURE__ */ A("div", {
111
+ D ? /* @__PURE__ */ j(u, { label: g("agents.loading", "Loading agents…") }) : B ? /* @__PURE__ */ j(l, {
112
+ message: g("agents.error", "Could not load agents."),
113
+ onRetry: () => void V()
114
+ }) : U.length === 0 ? /* @__PURE__ */ j("div", {
114
115
  className: "mt-6",
115
- children: /* @__PURE__ */ A(o, {
116
+ children: /* @__PURE__ */ j(o, {
116
117
  illustration: "empty-data",
117
- icon: /* @__PURE__ */ A(g, { className: "h-12 w-12" }),
118
- title: h("agents.emptyTitle", "No agents yet"),
119
- description: h("agents.emptyDescription", "Create your first AI agent to start automating discovery, renewals, or cost optimization."),
120
- action: /* @__PURE__ */ A("button", {
118
+ icon: /* @__PURE__ */ j(_, { className: "h-12 w-12" }),
119
+ title: g("agents.emptyTitle", "No agents yet"),
120
+ description: g("agents.emptyDescription", "Create your first AI agent to start automating discovery, renewals, or cost optimization."),
121
+ action: /* @__PURE__ */ j("button", {
121
122
  type: "button",
122
- onClick: () => _("/agents/new"),
123
+ onClick: () => v("/agents/new"),
123
124
  className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90",
124
- children: h("agents.newAgent", "New agent")
125
+ children: g("agents.newAgent", "New agent")
125
126
  })
126
127
  })
127
- }) : /* @__PURE__ */ j(k, { children: [/* @__PURE__ */ j("div", {
128
+ }) : /* @__PURE__ */ M(A, { children: [/* @__PURE__ */ M("div", {
128
129
  className: "mt-6 grid grid-cols-1 gap-4 lg:grid-cols-3",
129
- children: [/* @__PURE__ */ j(M, {
130
+ children: [/* @__PURE__ */ M(N, {
130
131
  treatment: "insight",
131
132
  className: "p-5 lg:col-span-1",
132
133
  children: [
133
- /* @__PURE__ */ A("p", {
134
+ /* @__PURE__ */ j("p", {
134
135
  className: "text-sm font-semibold text-text-primary",
135
- children: h("agents.fleet.title", "Fleet posture")
136
+ children: g("agents.fleet.title", "Fleet posture")
136
137
  }),
137
- /* @__PURE__ */ A("p", {
138
+ /* @__PURE__ */ j("p", {
138
139
  className: "mt-0.5 text-xs text-text-secondary",
139
- children: h("agents.fleet.description", "How your agents are allowed to act")
140
+ children: g("agents.fleet.description", "How your agents are allowed to act")
140
141
  }),
141
- /* @__PURE__ */ j("div", {
142
+ /* @__PURE__ */ M("div", {
142
143
  className: "mt-4 flex items-center gap-5",
143
- children: [/* @__PURE__ */ A(l, {
144
- data: K,
144
+ children: [/* @__PURE__ */ j(d, {
145
+ data: q,
145
146
  size: 132,
146
147
  thickness: 16,
147
- centerLabel: String(H.length),
148
- centerSub: H.length === 1 ? h("agents.fleet.agentSingular", "agent") : h("agents.fleet.agentPlural", "agents")
149
- }), /* @__PURE__ */ A(u, {
148
+ centerLabel: String(U.length),
149
+ centerSub: U.length === 1 ? g("agents.fleet.agentSingular", "agent") : g("agents.fleet.agentPlural", "agents")
150
+ }), /* @__PURE__ */ j(f, {
150
151
  className: "flex-1",
151
- data: K
152
+ data: q
152
153
  })]
153
154
  })
154
155
  ]
155
- }), /* @__PURE__ */ j("div", {
156
+ }), /* @__PURE__ */ M("div", {
156
157
  className: "grid grid-cols-2 gap-4 lg:col-span-2",
157
158
  children: [
158
- /* @__PURE__ */ A(n, {
159
- icon: /* @__PURE__ */ A(g, { className: "h-5 w-5" }),
160
- value: H.length,
161
- label: h("agents.fleet.totalAgents", "Total agents")
159
+ /* @__PURE__ */ j(n, {
160
+ icon: /* @__PURE__ */ j(_, { className: "h-5 w-5" }),
161
+ value: U.length,
162
+ label: g("agents.fleet.totalAgents", "Total agents")
162
163
  }),
163
- /* @__PURE__ */ A(n, {
164
- icon: /* @__PURE__ */ A(O, { className: "h-5 w-5" }),
165
- value: U.AUTONOMOUS,
166
- label: h("agents.postures.autonomous", "Autonomous")
164
+ /* @__PURE__ */ j(n, {
165
+ icon: /* @__PURE__ */ j(k, { className: "h-5 w-5" }),
166
+ value: W.AUTONOMOUS,
167
+ label: g("agents.postures.autonomous", "Autonomous")
167
168
  }),
168
- /* @__PURE__ */ A(n, {
169
- icon: /* @__PURE__ */ A(D, { className: "h-5 w-5" }),
170
- value: U.SUGGEST_ONLY,
171
- label: h("agents.postures.suggestOnly", "Suggest-only")
169
+ /* @__PURE__ */ j(n, {
170
+ icon: /* @__PURE__ */ j(O, { className: "h-5 w-5" }),
171
+ value: W.SUGGEST_ONLY,
172
+ label: g("agents.postures.suggestOnly", "Suggest-only")
172
173
  }),
173
- /* @__PURE__ */ A(n, {
174
- icon: /* @__PURE__ */ A(v, { className: "h-5 w-5" }),
175
- value: W,
176
- label: h("agents.fleet.ranLast7Days", "Ran in last 7 days")
174
+ /* @__PURE__ */ j(n, {
175
+ icon: /* @__PURE__ */ j(y, { className: "h-5 w-5" }),
176
+ value: G,
177
+ label: g("agents.fleet.ranLast7Days", "Ran in last 7 days")
177
178
  })
178
179
  ]
179
180
  })]
180
- }), /* @__PURE__ */ A("div", {
181
+ }), /* @__PURE__ */ j("div", {
181
182
  className: "mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
182
- children: H.map((e) => {
183
- let t = I[e.kind] ?? g;
184
- return /* @__PURE__ */ j(M, {
183
+ children: U.map((e) => {
184
+ let t = L[e.kind] ?? _;
185
+ return /* @__PURE__ */ M(N, {
185
186
  treatment: "metric",
186
187
  glow: e.status === "AUTONOMOUS",
187
188
  className: "flex flex-col p-5",
188
- children: [/* @__PURE__ */ j("button", {
189
+ children: [/* @__PURE__ */ M("button", {
189
190
  type: "button",
190
- onClick: () => _(`/agents/${e.id}`),
191
+ onClick: () => v(`/agents/${e.id}`),
191
192
  className: "rounded-lg text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
192
- "aria-label": h("agents.card.openAria", "Open {{name}}", { name: e.name }),
193
+ "aria-label": g("agents.card.openAria", "Open {{name}}", { name: e.name }),
193
194
  children: [
194
- /* @__PURE__ */ j("div", {
195
+ /* @__PURE__ */ M("div", {
195
196
  className: "flex items-start justify-between gap-2",
196
- children: [/* @__PURE__ */ A("span", {
197
+ children: [/* @__PURE__ */ j("span", {
197
198
  className: "flex size-10 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary",
198
- children: /* @__PURE__ */ A(t, { className: "h-5 w-5" })
199
- }), /* @__PURE__ */ A(a, { status: e.status })]
199
+ children: /* @__PURE__ */ j(t, { className: "h-5 w-5" })
200
+ }), /* @__PURE__ */ j(a, { status: e.status })]
200
201
  }),
201
- /* @__PURE__ */ A("p", {
202
+ /* @__PURE__ */ j("p", {
202
203
  className: "mt-3 truncate text-sm font-semibold text-text-primary",
203
204
  children: e.name
204
205
  }),
205
- /* @__PURE__ */ j("p", {
206
+ /* @__PURE__ */ M("p", {
206
207
  className: "text-xs text-text-secondary",
207
208
  children: [
208
- h(P[e.kind], r(e.kind)),
209
+ g(F[e.kind], r(e.kind)),
209
210
  " ",
210
- h("agents.card.kindSuffix", "agent")
211
+ g("agents.card.kindSuffix", "agent")
211
212
  ]
212
213
  }),
213
- /* @__PURE__ */ A("p", {
214
+ /* @__PURE__ */ j("p", {
214
215
  className: "mt-2 line-clamp-2 min-h-[2rem] text-xs text-text-secondary",
215
- children: e.description || h("agents.card.noDescription", "No description provided.")
216
+ children: e.description || g("agents.card.noDescription", "No description provided.")
216
217
  }),
217
- /* @__PURE__ */ j("p", {
218
+ /* @__PURE__ */ M("p", {
218
219
  className: "mt-3 flex items-center gap-1.5 text-xs text-text-secondary",
219
- children: [/* @__PURE__ */ A(v, {
220
+ children: [/* @__PURE__ */ j(y, {
220
221
  className: "h-3.5 w-3.5",
221
222
  "aria-hidden": !0
222
- }), e.lastRunAt ? h("agents.card.lastRun", "Last run {{when}}", { when: i(e.lastRunAt) }) : h("agents.card.neverRun", "Never run")]
223
+ }), e.lastRunAt ? g("agents.card.lastRun", "Last run {{when}}", { when: i(e.lastRunAt) }) : g("agents.card.neverRun", "Never run")]
223
224
  })
224
225
  ]
225
- }), /* @__PURE__ */ j("div", {
226
+ }), /* @__PURE__ */ M("div", {
226
227
  className: "mt-4 border-t border-border-subtle pt-3",
227
- children: [/* @__PURE__ */ A("label", {
228
+ children: [/* @__PURE__ */ j("label", {
228
229
  className: "mb-1 block text-[10px] font-medium uppercase tracking-wide text-text-secondary",
229
- children: h("agents.card.posture", "Posture")
230
- }), /* @__PURE__ */ A("select", {
231
- "aria-label": h("agents.card.postureAria", "Posture for {{name}}", { name: e.name }),
230
+ children: g("agents.card.posture", "Posture")
231
+ }), /* @__PURE__ */ j("select", {
232
+ "aria-label": g("agents.card.postureAria", "Posture for {{name}}", { name: e.name }),
232
233
  value: e.status,
233
- disabled: V.isPending,
234
- onChange: (t) => V.mutate({
234
+ disabled: H.isPending,
235
+ onChange: (t) => H.mutate({
235
236
  id: e.id,
236
237
  status: t.target.value
237
238
  }),
238
239
  className: "w-full rounded-lg border border-border-subtle bg-bg-surface px-2 py-1.5 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] disabled:opacity-50",
239
- children: F.map((e) => /* @__PURE__ */ A("option", {
240
- value: e,
241
- children: h(`agents.postures.${e.toLowerCase()}`, r(e))
242
- }, e))
240
+ children: /* @__PURE__ */ j(c, {
241
+ options: I,
242
+ currentStatus: e.status
243
+ })
243
244
  })]
244
245
  })]
245
246
  }, e.id);
@@ -249,6 +250,6 @@ function z() {
249
250
  });
250
251
  }
251
252
  //#endregion
252
- export { z as AgentsListPage };
253
+ export { B as AgentsListPage };
253
254
 
254
255
  //# sourceMappingURL=AgentsListPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AgentsListPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/agents/AgentsListPage.tsx"],"sourcesContent":["/**\n * AI Agents list\n * @module subscriberbot/pages/agents\n *\n * The AI Agents Framework — specialized agents (Discovery, Renewal, Cost,\n * Newsletter, Vendor, Compliance, Negotiation, Migration, Concierge) that each\n * own a slice of the recurring-relationship problem. Filter by kind / posture.\n * Reads `subListAgents`; sets posture inline via `subSetAgentStatus`.\n */\n\nimport { useState } from 'react';\nimport {\n Plus,\n Bot,\n Search,\n RefreshCw,\n DollarSign,\n Mail,\n Building2,\n ShieldCheck,\n Handshake,\n ArrowLeftRight,\n ConciergeBell,\n Clock,\n Zap,\n Sparkles,\n type LucideIcon,\n} from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n EmptyState,\n MetricsCard,\n Donut,\n Legend,\n LoadingView,\n ErrorView,\n type Segment,\n} from '../../components';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { useAgents, useSetAgentStatus } from '../../hooks/useSubscriberBotApi';\nimport { useTr } from '../../hooks/useTr';\nimport { formatEnumLabel, formatRelativeTime } from '../../utils/formatters';\nimport type { SubAgentKind, SubAgentStatus } from '../../types';\n\nconst KIND_KEY: Record<SubAgentKind, string> = {\n DISCOVERY: 'agents.kinds.discovery',\n RENEWAL: 'agents.kinds.renewal',\n COST: 'agents.kinds.cost',\n NEWSLETTER: 'agents.kinds.newsletter',\n VENDOR: 'agents.kinds.vendor',\n COMPLIANCE: 'agents.kinds.compliance',\n NEGOTIATION: 'agents.kinds.negotiation',\n MIGRATION: 'agents.kinds.migration',\n CONCIERGE: 'agents.kinds.concierge',\n};\n\nconst STATUS_OPTIONS: SubAgentStatus[] = ['DISABLED', 'SUGGEST_ONLY', 'AUTONOMOUS'];\n\n/** Kind → glyph. Purely presentational; falls back to the generic Bot mark. */\nconst KIND_ICON: Record<SubAgentKind, LucideIcon> = {\n DISCOVERY: Search,\n RENEWAL: RefreshCw,\n COST: DollarSign,\n NEWSLETTER: Mail,\n VENDOR: Building2,\n COMPLIANCE: ShieldCheck,\n NEGOTIATION: Handshake,\n MIGRATION: ArrowLeftRight,\n CONCIERGE: ConciergeBell,\n};\n\n/** Posture → semantic chart colour (tokens only) for the fleet donut. */\nconst POSTURE_COLOR: Record<SubAgentStatus, string> = {\n AUTONOMOUS: 'var(--color-status-success-text)',\n SUGGEST_ONLY: 'var(--color-accent-indigo)',\n DISABLED: 'var(--color-text-secondary)',\n};\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\nexport function AgentsListPage() {\n const tr = useTr();\n const { navigateTo } = useSubscriberBot();\n const [kind, setKind] = useState<'' | SubAgentKind>('');\n const [status, setStatus] = useState<'' | SubAgentStatus>('');\n\n const kindOptions: Array<{ value: '' | SubAgentKind; label: string }> = [\n { value: '', label: tr('agents.filters.allKinds', 'All kinds') },\n ...Object.entries(KIND_KEY).map(([value, key]) => ({\n value: value as SubAgentKind,\n label: tr(key, formatEnumLabel(value as SubAgentKind)),\n })),\n ];\n\n const { data, isLoading, isError, refetch } = useAgents({\n kind: kind || undefined,\n status: status || undefined,\n });\n const setAgentStatus = useSetAgentStatus();\n\n const agents = data ?? [];\n\n // --- Real, computed fleet aggregates (never hardcoded) --------------------\n const postureCounts: Record<SubAgentStatus, number> = {\n AUTONOMOUS: 0,\n SUGGEST_ONLY: 0,\n DISABLED: 0,\n };\n let recentlyRun = 0;\n const now = Date.now();\n for (const a of agents) {\n postureCounts[a.status] += 1;\n if (a.lastRunAt && now - new Date(a.lastRunAt).getTime() <= 7 * DAY_MS) recentlyRun += 1;\n }\n const postureData: Segment[] = STATUS_OPTIONS.map((s) => ({\n label: tr(`agents.postures.${s.toLowerCase()}`, formatEnumLabel(s)),\n value: postureCounts[s],\n color: POSTURE_COLOR[s],\n })).filter((d) => d.value > 0);\n\n return (\n <PageLayout\n title={tr('agents.title', 'AI Agents')}\n description={tr(\n 'agents.description',\n 'Specialized agents that automate your recurring portfolio'\n )}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/agents/new')}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n <Plus className=\"h-4 w-4\" /> {tr('agents.newAgent', 'New agent')}\n </button>\n }\n >\n <PagePurpose className=\"mb-4\">\n {tr(\n 'agents.purpose',\n \"Agents propose; your policies decide what they may do autonomously. Set each agent's posture — Disabled, Suggest-only, or Autonomous — and open one to review its policies.\"\n )}\n </PagePurpose>\n\n <div className=\"flex flex-wrap items-center gap-3\">\n <select\n aria-label={tr('agents.filters.kindLabel', 'Filter by kind')}\n value={kind}\n onChange={(e) => setKind(e.target.value as '' | SubAgentKind)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {kindOptions.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n <select\n aria-label={tr('agents.filters.postureLabel', 'Filter by posture')}\n value={status}\n onChange={(e) => setStatus(e.target.value as '' | SubAgentStatus)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">{tr('agents.filters.anyPosture', 'Any posture')}</option>\n {STATUS_OPTIONS.map((s) => (\n <option key={s} value={s}>\n {tr(`agents.postures.${s.toLowerCase()}`, formatEnumLabel(s))}\n </option>\n ))}\n </select>\n </div>\n\n {isLoading ? (\n <LoadingView label={tr('agents.loading', 'Loading agents…')} />\n ) : isError ? (\n <ErrorView\n message={tr('agents.error', 'Could not load agents.')}\n onRetry={() => void refetch()}\n />\n ) : agents.length === 0 ? (\n <div className=\"mt-6\">\n <EmptyState\n illustration=\"empty-data\"\n icon={<Bot className=\"h-12 w-12\" />}\n title={tr('agents.emptyTitle', 'No agents yet')}\n description={tr(\n 'agents.emptyDescription',\n 'Create your first AI agent to start automating discovery, renewals, or cost optimization.'\n )}\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/agents/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n {tr('agents.newAgent', 'New agent')}\n </button>\n }\n />\n </div>\n ) : (\n <>\n {/* --- Fleet overview: posture mix + live counts (computed) ------ */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 lg:grid-cols-3\">\n <GlassCard treatment=\"insight\" className=\"p-5 lg:col-span-1\">\n <p className=\"text-sm font-semibold text-text-primary\">\n {tr('agents.fleet.title', 'Fleet posture')}\n </p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr('agents.fleet.description', 'How your agents are allowed to act')}\n </p>\n <div className=\"mt-4 flex items-center gap-5\">\n <Donut\n data={postureData}\n size={132}\n thickness={16}\n centerLabel={String(agents.length)}\n centerSub={\n agents.length === 1\n ? tr('agents.fleet.agentSingular', 'agent')\n : tr('agents.fleet.agentPlural', 'agents')\n }\n />\n <Legend className=\"flex-1\" data={postureData} />\n </div>\n </GlassCard>\n\n <div className=\"grid grid-cols-2 gap-4 lg:col-span-2\">\n <MetricsCard\n icon={<Bot className=\"h-5 w-5\" />}\n value={agents.length}\n label={tr('agents.fleet.totalAgents', 'Total agents')}\n />\n <MetricsCard\n icon={<Zap className=\"h-5 w-5\" />}\n value={postureCounts.AUTONOMOUS}\n label={tr('agents.postures.autonomous', 'Autonomous')}\n />\n <MetricsCard\n icon={<Sparkles className=\"h-5 w-5\" />}\n value={postureCounts.SUGGEST_ONLY}\n label={tr('agents.postures.suggestOnly', 'Suggest-only')}\n />\n <MetricsCard\n icon={<Clock className=\"h-5 w-5\" />}\n value={recentlyRun}\n label={tr('agents.fleet.ranLast7Days', 'Ran in last 7 days')}\n />\n </div>\n </div>\n\n {/* --- Agent cards ------------------------------------------------ */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {agents.map((a) => {\n const Icon = KIND_ICON[a.kind] ?? Bot;\n return (\n <GlassCard\n key={a.id}\n treatment=\"metric\"\n glow={a.status === 'AUTONOMOUS'}\n className=\"flex flex-col p-5\"\n >\n <button\n type=\"button\"\n onClick={() => navigateTo(`/agents/${a.id}`)}\n className=\"rounded-lg text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n aria-label={tr('agents.card.openAria', 'Open {{name}}', { name: a.name })}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"flex size-10 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <StatusBadge status={a.status} />\n </div>\n <p className=\"mt-3 truncate text-sm font-semibold text-text-primary\">\n {a.name}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {tr(KIND_KEY[a.kind], formatEnumLabel(a.kind))}{' '}\n {tr('agents.card.kindSuffix', 'agent')}\n </p>\n <p className=\"mt-2 line-clamp-2 min-h-[2rem] text-xs text-text-secondary\">\n {a.description || tr('agents.card.noDescription', 'No description provided.')}\n </p>\n <p className=\"mt-3 flex items-center gap-1.5 text-xs text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5\" aria-hidden />\n {a.lastRunAt\n ? tr('agents.card.lastRun', 'Last run {{when}}', {\n when: formatRelativeTime(a.lastRunAt),\n })\n : tr('agents.card.neverRun', 'Never run')}\n </p>\n </button>\n <div className=\"mt-4 border-t border-border-subtle pt-3\">\n <label className=\"mb-1 block text-[10px] font-medium uppercase tracking-wide text-text-secondary\">\n {tr('agents.card.posture', 'Posture')}\n </label>\n <select\n aria-label={tr('agents.card.postureAria', 'Posture for {{name}}', {\n name: a.name,\n })}\n value={a.status}\n disabled={setAgentStatus.isPending}\n onChange={(e) =>\n setAgentStatus.mutate({\n id: a.id,\n status: e.target.value as SubAgentStatus,\n })\n }\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-2 py-1.5 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] disabled:opacity-50\"\n >\n {STATUS_OPTIONS.map((s) => (\n <option key={s} value={s}>\n {tr(`agents.postures.${s.toLowerCase()}`, formatEnumLabel(s))}\n </option>\n ))}\n </select>\n </div>\n </GlassCard>\n );\n })}\n </div>\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentsListPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/agents/AgentsListPage.tsx"],"sourcesContent":["/**\n * AI Agents list\n * @module subscriberbot/pages/agents\n *\n * The AI Agents Framework — specialized agents (Discovery, Renewal, Cost,\n * Newsletter, Vendor, Compliance, Negotiation, Migration, Concierge) that each\n * own a slice of the recurring-relationship problem. Filter by kind / posture.\n * Reads `subListAgents`; sets posture inline via `subSetAgentStatus`.\n */\n\nimport { useState } from 'react';\nimport {\n Plus,\n Bot,\n Search,\n RefreshCw,\n DollarSign,\n Mail,\n Building2,\n ShieldCheck,\n Handshake,\n ArrowLeftRight,\n ConciergeBell,\n Clock,\n Zap,\n Sparkles,\n type LucideIcon,\n} from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n EmptyState,\n MetricsCard,\n Donut,\n Legend,\n LoadingView,\n ErrorView,\n type Segment,\n} from '../../components';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { useAgents, useSetAgentStatus } from '../../hooks/useSubscriberBotApi';\nimport { useTr } from '../../hooks/useTr';\nimport { PostureOptions } from '../../components/PostureOptions';\nimport { formatEnumLabel, formatRelativeTime } from '../../utils/formatters';\nimport type { SubAgentKind, SubAgentStatus } from '../../types';\n\nconst KIND_KEY: Record<SubAgentKind, string> = {\n DISCOVERY: 'agents.kinds.discovery',\n RENEWAL: 'agents.kinds.renewal',\n COST: 'agents.kinds.cost',\n NEWSLETTER: 'agents.kinds.newsletter',\n VENDOR: 'agents.kinds.vendor',\n COMPLIANCE: 'agents.kinds.compliance',\n NEGOTIATION: 'agents.kinds.negotiation',\n MIGRATION: 'agents.kinds.migration',\n CONCIERGE: 'agents.kinds.concierge',\n};\n\nconst STATUS_OPTIONS: SubAgentStatus[] = ['DISABLED', 'SUGGEST_ONLY', 'AUTONOMOUS'];\n\n/** Kind → glyph. Purely presentational; falls back to the generic Bot mark. */\nconst KIND_ICON: Record<SubAgentKind, LucideIcon> = {\n DISCOVERY: Search,\n RENEWAL: RefreshCw,\n COST: DollarSign,\n NEWSLETTER: Mail,\n VENDOR: Building2,\n COMPLIANCE: ShieldCheck,\n NEGOTIATION: Handshake,\n MIGRATION: ArrowLeftRight,\n CONCIERGE: ConciergeBell,\n};\n\n/** Posture → semantic chart colour (tokens only) for the fleet donut. */\nconst POSTURE_COLOR: Record<SubAgentStatus, string> = {\n AUTONOMOUS: 'var(--color-status-success-text)',\n SUGGEST_ONLY: 'var(--color-accent-indigo)',\n DISABLED: 'var(--color-text-secondary)',\n};\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\nexport function AgentsListPage() {\n const tr = useTr();\n const { navigateTo } = useSubscriberBot();\n const [kind, setKind] = useState<'' | SubAgentKind>('');\n const [status, setStatus] = useState<'' | SubAgentStatus>('');\n\n const kindOptions: Array<{ value: '' | SubAgentKind; label: string }> = [\n { value: '', label: tr('agents.filters.allKinds', 'All kinds') },\n ...Object.entries(KIND_KEY).map(([value, key]) => ({\n value: value as SubAgentKind,\n label: tr(key, formatEnumLabel(value as SubAgentKind)),\n })),\n ];\n\n const { data, isLoading, isError, refetch } = useAgents({\n kind: kind || undefined,\n status: status || undefined,\n });\n const setAgentStatus = useSetAgentStatus();\n\n const agents = data ?? [];\n\n // --- Real, computed fleet aggregates (never hardcoded) --------------------\n const postureCounts: Record<SubAgentStatus, number> = {\n AUTONOMOUS: 0,\n SUGGEST_ONLY: 0,\n DISABLED: 0,\n };\n let recentlyRun = 0;\n const now = Date.now();\n for (const a of agents) {\n postureCounts[a.status] += 1;\n if (a.lastRunAt && now - new Date(a.lastRunAt).getTime() <= 7 * DAY_MS) recentlyRun += 1;\n }\n const postureData: Segment[] = STATUS_OPTIONS.map((s) => ({\n label: tr(`agents.postures.${s.toLowerCase()}`, formatEnumLabel(s)),\n value: postureCounts[s],\n color: POSTURE_COLOR[s],\n })).filter((d) => d.value > 0);\n\n return (\n <PageLayout\n title={tr('agents.title', 'AI Agents')}\n description={tr(\n 'agents.description',\n 'Specialized agents that automate your recurring portfolio'\n )}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/agents/new')}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n <Plus className=\"h-4 w-4\" /> {tr('agents.newAgent', 'New agent')}\n </button>\n }\n >\n <PagePurpose className=\"mb-4\">\n {tr(\n 'agents.purpose',\n \"Agents propose; your policies decide what they may do autonomously. Set each agent's posture — Disabled, Suggest-only, or Autonomous — and open one to review its policies.\"\n )}\n </PagePurpose>\n\n <div className=\"flex flex-wrap items-center gap-3\">\n <select\n aria-label={tr('agents.filters.kindLabel', 'Filter by kind')}\n value={kind}\n onChange={(e) => setKind(e.target.value as '' | SubAgentKind)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {kindOptions.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n <select\n aria-label={tr('agents.filters.postureLabel', 'Filter by posture')}\n value={status}\n onChange={(e) => setStatus(e.target.value as '' | SubAgentStatus)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">{tr('agents.filters.anyPosture', 'Any posture')}</option>\n {STATUS_OPTIONS.map((s) => (\n <option key={s} value={s}>\n {tr(`agents.postures.${s.toLowerCase()}`, formatEnumLabel(s))}\n </option>\n ))}\n </select>\n </div>\n\n {isLoading ? (\n <LoadingView label={tr('agents.loading', 'Loading agents…')} />\n ) : isError ? (\n <ErrorView\n message={tr('agents.error', 'Could not load agents.')}\n onRetry={() => void refetch()}\n />\n ) : agents.length === 0 ? (\n <div className=\"mt-6\">\n <EmptyState\n illustration=\"empty-data\"\n icon={<Bot className=\"h-12 w-12\" />}\n title={tr('agents.emptyTitle', 'No agents yet')}\n description={tr(\n 'agents.emptyDescription',\n 'Create your first AI agent to start automating discovery, renewals, or cost optimization.'\n )}\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/agents/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n {tr('agents.newAgent', 'New agent')}\n </button>\n }\n />\n </div>\n ) : (\n <>\n {/* --- Fleet overview: posture mix + live counts (computed) ------ */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 lg:grid-cols-3\">\n <GlassCard treatment=\"insight\" className=\"p-5 lg:col-span-1\">\n <p className=\"text-sm font-semibold text-text-primary\">\n {tr('agents.fleet.title', 'Fleet posture')}\n </p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {tr('agents.fleet.description', 'How your agents are allowed to act')}\n </p>\n <div className=\"mt-4 flex items-center gap-5\">\n <Donut\n data={postureData}\n size={132}\n thickness={16}\n centerLabel={String(agents.length)}\n centerSub={\n agents.length === 1\n ? tr('agents.fleet.agentSingular', 'agent')\n : tr('agents.fleet.agentPlural', 'agents')\n }\n />\n <Legend className=\"flex-1\" data={postureData} />\n </div>\n </GlassCard>\n\n <div className=\"grid grid-cols-2 gap-4 lg:col-span-2\">\n <MetricsCard\n icon={<Bot className=\"h-5 w-5\" />}\n value={agents.length}\n label={tr('agents.fleet.totalAgents', 'Total agents')}\n />\n <MetricsCard\n icon={<Zap className=\"h-5 w-5\" />}\n value={postureCounts.AUTONOMOUS}\n label={tr('agents.postures.autonomous', 'Autonomous')}\n />\n <MetricsCard\n icon={<Sparkles className=\"h-5 w-5\" />}\n value={postureCounts.SUGGEST_ONLY}\n label={tr('agents.postures.suggestOnly', 'Suggest-only')}\n />\n <MetricsCard\n icon={<Clock className=\"h-5 w-5\" />}\n value={recentlyRun}\n label={tr('agents.fleet.ranLast7Days', 'Ran in last 7 days')}\n />\n </div>\n </div>\n\n {/* --- Agent cards ------------------------------------------------ */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {agents.map((a) => {\n const Icon = KIND_ICON[a.kind] ?? Bot;\n return (\n <GlassCard\n key={a.id}\n treatment=\"metric\"\n glow={a.status === 'AUTONOMOUS'}\n className=\"flex flex-col p-5\"\n >\n <button\n type=\"button\"\n onClick={() => navigateTo(`/agents/${a.id}`)}\n className=\"rounded-lg text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n aria-label={tr('agents.card.openAria', 'Open {{name}}', { name: a.name })}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"flex size-10 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <StatusBadge status={a.status} />\n </div>\n <p className=\"mt-3 truncate text-sm font-semibold text-text-primary\">\n {a.name}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {tr(KIND_KEY[a.kind], formatEnumLabel(a.kind))}{' '}\n {tr('agents.card.kindSuffix', 'agent')}\n </p>\n <p className=\"mt-2 line-clamp-2 min-h-[2rem] text-xs text-text-secondary\">\n {a.description || tr('agents.card.noDescription', 'No description provided.')}\n </p>\n <p className=\"mt-3 flex items-center gap-1.5 text-xs text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5\" aria-hidden />\n {a.lastRunAt\n ? tr('agents.card.lastRun', 'Last run {{when}}', {\n when: formatRelativeTime(a.lastRunAt),\n })\n : tr('agents.card.neverRun', 'Never run')}\n </p>\n </button>\n <div className=\"mt-4 border-t border-border-subtle pt-3\">\n <label className=\"mb-1 block text-[10px] font-medium uppercase tracking-wide text-text-secondary\">\n {tr('agents.card.posture', 'Posture')}\n </label>\n <select\n aria-label={tr('agents.card.postureAria', 'Posture for {{name}}', {\n name: a.name,\n })}\n value={a.status}\n disabled={setAgentStatus.isPending}\n onChange={(e) =>\n setAgentStatus.mutate({\n id: a.id,\n status: e.target.value as SubAgentStatus,\n })\n }\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-2 py-1.5 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] disabled:opacity-50\"\n >\n <PostureOptions options={STATUS_OPTIONS} currentStatus={a.status} />\n </select>\n </div>\n </GlassCard>\n );\n })}\n </div>\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}