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