@burdenoff/microfe-subscriberbot 2026.706.1 → 2026.706.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.
Files changed (23) hide show
  1. package/dist/subscriberbot/components/Modal.js +51 -0
  2. package/dist/subscriberbot/components/Modal.js.map +1 -0
  3. package/dist/subscriberbot/hooks/useSubscriberBotApi.js +358 -163
  4. package/dist/subscriberbot/hooks/useSubscriberBotApi.js.map +1 -1
  5. package/dist/subscriberbot/pages/InboxPage.js +339 -66
  6. package/dist/subscriberbot/pages/InboxPage.js.map +1 -1
  7. package/dist/subscriberbot/pages/InvoicesPage.js +496 -73
  8. package/dist/subscriberbot/pages/InvoicesPage.js.map +1 -1
  9. package/dist/subscriberbot/pages/WorkflowsPage.js +136 -150
  10. package/dist/subscriberbot/pages/WorkflowsPage.js.map +1 -1
  11. package/dist/subscriberbot/pages/agents/AgentDetailPage.js +197 -58
  12. package/dist/subscriberbot/pages/agents/AgentDetailPage.js.map +1 -1
  13. package/dist/subscriberbot/pages/agents/AgentsListPage.js +2 -0
  14. package/dist/subscriberbot/pages/agents/AgentsListPage.js.map +1 -1
  15. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js +538 -71
  16. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js.map +1 -1
  17. package/dist/subscriberbot/pages/providers/ProvidersListPage.js +2 -0
  18. package/dist/subscriberbot/pages/providers/ProvidersListPage.js.map +1 -1
  19. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js +664 -126
  20. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -1
  21. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js +18 -16
  22. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js.map +1 -1
  23. package/package.json +1 -1
@@ -4,141 +4,276 @@ import { formatEnumLabel as n, formatRelativeTime as r } from "../../utils/forma
4
4
  import { StatusBadge as i } from "../../components/StatusBadge.js";
5
5
  import { EmptyState as a } from "../../components/EmptyState.js";
6
6
  import { ErrorView as o, LoadingView as s, Section as c } from "../../components/StateViews.js";
7
- import { useAgent as l, useSetAgentStatus as u } from "../../hooks/useSubscriberBotApi.js";
8
- import { useState as d } from "react";
9
- import { ArrowLeft as f, Bot as p, ShieldCheck as m } from "lucide-react";
10
- import { useParams as h } from "react-router-dom";
11
- import { jsx as g, jsxs as _ } from "react/jsx-runtime";
12
- import { GlassCard as v } from "@burdenoff/fe-libs/ui";
7
+ import { useAgent as l, useCreatePolicy as u, useSetAgentStatus as d } from "../../hooks/useSubscriberBotApi.js";
8
+ import { Modal as f } from "../../components/Modal.js";
9
+ import { useState as p } from "react";
10
+ import { ArrowLeft as m, Bot as h, Plus as g, ShieldCheck as _ } from "lucide-react";
11
+ import { useParams as v } from "react-router-dom";
12
+ import { jsx as y, jsxs as b } from "react/jsx-runtime";
13
+ import { GlassCard as x } from "@burdenoff/fe-libs/ui";
13
14
  //#region src/subscriberbot/pages/agents/AgentDetailPage.tsx
14
- var y = [
15
+ var S = [
15
16
  "DISABLED",
16
17
  "SUGGEST_ONLY",
17
18
  "AUTONOMOUS"
18
- ];
19
- function b() {
20
- let { id: b } = h(), { navigateTo: x } = e(), { data: S, isLoading: C, isError: w, refetch: T } = l(b), E = u(), [D, O] = d(null);
21
- if (C) return /* @__PURE__ */ g(t, {
19
+ ], C = [
20
+ "ALERT",
21
+ "CREATE_TASK",
22
+ "RENEW",
23
+ "CANCEL",
24
+ "PAUSE",
25
+ "UPGRADE",
26
+ "DOWNGRADE"
27
+ ], w = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]", T = "mb-1 block text-xs font-medium text-text-secondary";
28
+ function E({ agentId: e, onClose: t }) {
29
+ let n = u(), [r, i] = p(""), [a, o] = p("ALERT"), [s, c] = p(""), [l, d] = p(""), [m, h] = p(!0), [g, _] = p(null);
30
+ return /* @__PURE__ */ y(f, {
31
+ title: "Add policy",
32
+ onClose: t,
33
+ maxWidthClassName: "max-w-xl",
34
+ children: /* @__PURE__ */ b("form", {
35
+ onSubmit: (i) => {
36
+ if (i.preventDefault(), _(null), !r.trim()) {
37
+ _("A policy name is required.");
38
+ return;
39
+ }
40
+ let o;
41
+ if (l.trim()) try {
42
+ o = JSON.parse(l);
43
+ } catch {
44
+ _("Condition must be valid JSON (e.g. {\"amountOver\": 100}).");
45
+ return;
46
+ }
47
+ n.mutate({
48
+ agentId: e,
49
+ name: r.trim(),
50
+ action: a,
51
+ isEnabled: m,
52
+ ...s.trim() ? { description: s.trim() } : {},
53
+ ...o ? { condition: o } : {}
54
+ }, {
55
+ onSuccess: () => t(),
56
+ onError: (e) => _(e instanceof Error ? e.message : "Could not add policy.")
57
+ });
58
+ },
59
+ className: "space-y-4",
60
+ children: [
61
+ g && /* @__PURE__ */ y("div", {
62
+ className: "rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text",
63
+ children: g
64
+ }),
65
+ /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ b("label", {
66
+ htmlFor: "policy-name",
67
+ className: T,
68
+ children: ["Name ", /* @__PURE__ */ y("span", {
69
+ className: "text-status-error-text",
70
+ children: "*"
71
+ })]
72
+ }), /* @__PURE__ */ y("input", {
73
+ id: "policy-name",
74
+ type: "text",
75
+ value: r,
76
+ onChange: (e) => i(e.target.value),
77
+ placeholder: "e.g. Alert on price hike over 20%",
78
+ className: w,
79
+ required: !0
80
+ })] }),
81
+ /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
82
+ htmlFor: "policy-action",
83
+ className: T,
84
+ children: "Action"
85
+ }), /* @__PURE__ */ y("select", {
86
+ id: "policy-action",
87
+ value: a,
88
+ onChange: (e) => o(e.target.value),
89
+ className: w,
90
+ children: C.map((e) => /* @__PURE__ */ y("option", {
91
+ value: e,
92
+ children: e.replace(/_/g, " ")
93
+ }, e))
94
+ })] }),
95
+ /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ b("label", {
96
+ htmlFor: "policy-condition",
97
+ className: T,
98
+ children: ["Condition ", /* @__PURE__ */ y("span", {
99
+ className: "text-text-secondary",
100
+ children: "(optional JSON)"
101
+ })]
102
+ }), /* @__PURE__ */ y("textarea", {
103
+ id: "policy-condition",
104
+ value: l,
105
+ onChange: (e) => d(e.target.value),
106
+ rows: 3,
107
+ placeholder: "{ \"priceIncreasePct\": 20 }",
108
+ className: `${w} font-mono`
109
+ })] }),
110
+ /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("label", {
111
+ htmlFor: "policy-desc",
112
+ className: T,
113
+ children: "Description"
114
+ }), /* @__PURE__ */ y("textarea", {
115
+ id: "policy-desc",
116
+ value: s,
117
+ onChange: (e) => c(e.target.value),
118
+ rows: 2,
119
+ className: w
120
+ })] }),
121
+ /* @__PURE__ */ b("label", {
122
+ className: "flex items-center gap-2 text-sm text-text-primary",
123
+ children: [/* @__PURE__ */ y("input", {
124
+ type: "checkbox",
125
+ checked: m,
126
+ onChange: (e) => h(e.target.checked),
127
+ className: "size-4 rounded border-border-subtle"
128
+ }), "Enabled"]
129
+ }),
130
+ /* @__PURE__ */ b("div", {
131
+ className: "flex justify-end gap-3",
132
+ children: [/* @__PURE__ */ y("button", {
133
+ type: "button",
134
+ onClick: t,
135
+ className: "rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
136
+ children: "Cancel"
137
+ }), /* @__PURE__ */ y("button", {
138
+ type: "submit",
139
+ disabled: n.isPending,
140
+ className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50",
141
+ children: n.isPending ? "Adding…" : "Add policy"
142
+ })]
143
+ })
144
+ ]
145
+ })
146
+ });
147
+ }
148
+ function D() {
149
+ let { id: u } = v(), { navigateTo: f } = e(), { data: C, isLoading: w, isError: T, refetch: D } = l(u), O = d(), [k, A] = p(null), [j, M] = p(!1);
150
+ if (w) return /* @__PURE__ */ y(t, {
22
151
  title: "Agent",
23
- children: /* @__PURE__ */ g(s, { label: "Loading agent…" })
152
+ children: /* @__PURE__ */ y(s, { label: "Loading agent…" })
24
153
  });
25
- if (w) return /* @__PURE__ */ g(t, {
154
+ if (T) return /* @__PURE__ */ y(t, {
26
155
  title: "Agent",
27
- children: /* @__PURE__ */ g(o, {
156
+ children: /* @__PURE__ */ y(o, {
28
157
  message: "Could not load this agent.",
29
- onRetry: () => void T()
158
+ onRetry: () => void D()
30
159
  })
31
160
  });
32
- if (!S) return /* @__PURE__ */ g(t, {
161
+ if (!C) return /* @__PURE__ */ y(t, {
33
162
  title: "Agent",
34
- children: /* @__PURE__ */ g(a, {
163
+ children: /* @__PURE__ */ y(a, {
35
164
  illustration: "empty-data",
36
165
  title: "Agent not found",
37
166
  description: "It may have been removed, or you may not have access to it.",
38
- action: /* @__PURE__ */ g("button", {
167
+ action: /* @__PURE__ */ y("button", {
39
168
  type: "button",
40
- onClick: () => x("/agents"),
169
+ onClick: () => f("/agents"),
41
170
  className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90",
42
171
  children: "Back to agents"
43
172
  })
44
173
  })
45
174
  });
46
- let k = S;
47
- return /* @__PURE__ */ _(t, {
48
- title: k.name,
49
- description: `${n(k.kind)} agent`,
50
- actions: /* @__PURE__ */ _("button", {
175
+ let N = C;
176
+ return /* @__PURE__ */ b(t, {
177
+ title: N.name,
178
+ description: `${n(N.kind)} agent`,
179
+ actions: /* @__PURE__ */ b("button", {
51
180
  type: "button",
52
- onClick: () => x("/agents"),
181
+ onClick: () => f("/agents"),
53
182
  className: "inline-flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
54
- children: [/* @__PURE__ */ g(f, { className: "h-4 w-4" }), " Back"]
183
+ children: [/* @__PURE__ */ y(m, { className: "h-4 w-4" }), " Back"]
55
184
  }),
56
185
  children: [
57
- /* @__PURE__ */ _("div", {
186
+ /* @__PURE__ */ b("div", {
58
187
  className: "flex flex-wrap items-center gap-3",
59
188
  children: [
60
- /* @__PURE__ */ g("span", {
189
+ /* @__PURE__ */ y("span", {
61
190
  className: "flex size-10 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary",
62
- children: /* @__PURE__ */ g(p, { className: "h-5 w-5" })
191
+ children: /* @__PURE__ */ y(h, { className: "h-5 w-5" })
63
192
  }),
64
- /* @__PURE__ */ g(i, { status: k.status }),
65
- /* @__PURE__ */ g("span", {
193
+ /* @__PURE__ */ y(i, { status: N.status }),
194
+ /* @__PURE__ */ y("span", {
66
195
  className: "text-sm text-text-secondary",
67
- children: k.lastRunAt ? `Last run ${r(k.lastRunAt)}` : "Never run"
196
+ children: N.lastRunAt ? `Last run ${r(N.lastRunAt)}` : "Never run"
68
197
  })
69
198
  ]
70
199
  }),
71
- k.description && /* @__PURE__ */ g("p", {
200
+ N.description && /* @__PURE__ */ y("p", {
72
201
  className: "mt-4 max-w-3xl text-sm text-text-secondary",
73
- children: k.description
202
+ children: N.description
74
203
  }),
75
- D && /* @__PURE__ */ g("div", {
204
+ k && /* @__PURE__ */ y("div", {
76
205
  className: "mt-4 rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text",
77
- children: D
206
+ children: k
78
207
  }),
79
- /* @__PURE__ */ _("div", {
208
+ /* @__PURE__ */ b("div", {
80
209
  className: "mt-6 max-w-sm",
81
210
  children: [
82
- /* @__PURE__ */ g("label", {
211
+ /* @__PURE__ */ y("label", {
83
212
  htmlFor: "agent-posture",
84
213
  className: "mb-1 block text-xs font-medium text-text-secondary",
85
214
  children: "Operating posture"
86
215
  }),
87
- /* @__PURE__ */ g("select", {
216
+ /* @__PURE__ */ y("select", {
88
217
  id: "agent-posture",
89
- value: k.status,
90
- disabled: E.isPending,
218
+ value: N.status,
219
+ disabled: O.isPending,
91
220
  onChange: (e) => {
92
- O(null), E.mutate({
93
- id: k.id,
221
+ A(null), O.mutate({
222
+ id: N.id,
94
223
  status: e.target.value
95
- }, { onError: (e) => O(e instanceof Error ? e.message : "Could not change posture.") });
224
+ }, { onError: (e) => A(e instanceof Error ? e.message : "Could not change posture.") });
96
225
  },
97
226
  className: "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] disabled:opacity-50",
98
- children: y.map((e) => /* @__PURE__ */ g("option", {
227
+ children: S.map((e) => /* @__PURE__ */ y("option", {
99
228
  value: e,
100
229
  children: n(e)
101
230
  }, e))
102
231
  }),
103
- /* @__PURE__ */ g("p", {
232
+ /* @__PURE__ */ y("p", {
104
233
  className: "mt-1.5 text-xs text-text-secondary",
105
234
  children: "Disabled never acts; Suggest-only proposes; Autonomous acts within its policies."
106
235
  })
107
236
  ]
108
237
  }),
109
- /* @__PURE__ */ g(c, {
238
+ /* @__PURE__ */ y(c, {
110
239
  title: "Policies",
111
240
  description: "The autonomous rules that bound this agent",
112
- children: !k.policies || k.policies.length === 0 ? /* @__PURE__ */ g(a, {
241
+ action: /* @__PURE__ */ b("button", {
242
+ type: "button",
243
+ onClick: () => M(!0),
244
+ className: "inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken",
245
+ children: [/* @__PURE__ */ y(g, { className: "h-3.5 w-3.5" }), " Add policy"]
246
+ }),
247
+ children: !N.policies || N.policies.length === 0 ? /* @__PURE__ */ y(a, {
113
248
  illustration: "empty-data",
114
249
  title: "No policies",
115
250
  description: "Policies define what this agent may do autonomously, and what it must alert on."
116
- }) : /* @__PURE__ */ g("div", {
251
+ }) : /* @__PURE__ */ y("div", {
117
252
  className: "grid grid-cols-1 gap-3 sm:grid-cols-2",
118
- children: k.policies.map((e) => /* @__PURE__ */ _(v, {
253
+ children: N.policies.map((e) => /* @__PURE__ */ b(x, {
119
254
  treatment: "metric",
120
255
  className: "p-4",
121
256
  children: [
122
- /* @__PURE__ */ _("div", {
257
+ /* @__PURE__ */ b("div", {
123
258
  className: "flex items-start justify-between gap-2",
124
- children: [/* @__PURE__ */ g("p", {
259
+ children: [/* @__PURE__ */ y("p", {
125
260
  className: "text-sm font-medium text-text-primary",
126
261
  children: e.name
127
- }), /* @__PURE__ */ g(i, { status: e.isEnabled ? "ACTIVE" : "DISABLED" })]
262
+ }), /* @__PURE__ */ y(i, { status: e.isEnabled ? "ACTIVE" : "DISABLED" })]
128
263
  }),
129
- /* @__PURE__ */ _("p", {
264
+ /* @__PURE__ */ b("p", {
130
265
  className: "mt-1 flex items-center gap-1.5 text-xs text-text-secondary",
131
266
  children: [
132
- /* @__PURE__ */ g(m, { className: "h-3.5 w-3.5" }),
267
+ /* @__PURE__ */ y(_, { className: "h-3.5 w-3.5" }),
133
268
  " Action: ",
134
269
  n(e.action)
135
270
  ]
136
271
  }),
137
- e.description && /* @__PURE__ */ g("p", {
272
+ e.description && /* @__PURE__ */ y("p", {
138
273
  className: "mt-2 text-xs text-text-secondary",
139
274
  children: e.description
140
275
  }),
141
- /* @__PURE__ */ _("p", {
276
+ /* @__PURE__ */ b("p", {
142
277
  className: "mt-2 text-xs text-text-secondary",
143
278
  children: [
144
279
  "Triggered ",
@@ -150,11 +285,15 @@ function b() {
150
285
  ]
151
286
  }, e.id))
152
287
  })
288
+ }),
289
+ j && /* @__PURE__ */ y(E, {
290
+ agentId: N.id,
291
+ onClose: () => M(!1)
153
292
  })
154
293
  ]
155
294
  });
156
295
  }
157
296
  //#endregion
158
- export { b as AgentDetailPage };
297
+ export { D as AgentDetailPage };
159
298
 
160
299
  //# sourceMappingURL=AgentDetailPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AgentDetailPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/agents/AgentDetailPage.tsx"],"sourcesContent":["/**\n * Agent detail\n * @module subscriberbot/pages/agents\n *\n * A single AI agent: its kind, posture, last run, and the autonomous policies\n * that bound it. Reads `subAgent(id)`; changes posture via `subSetAgentStatus`.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Bot, ShieldCheck } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView, Section } from '../../components/StateViews';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { useAgent, useSetAgentStatus } from '../../hooks/useSubscriberBotApi';\nimport { formatEnumLabel, formatRelativeTime } from '../../utils/formatters';\nimport type { SubAgentStatus } from '../../types';\n\nconst STATUS_OPTIONS: SubAgentStatus[] = ['DISABLED', 'SUGGEST_ONLY', 'AUTONOMOUS'];\n\nexport function AgentDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useSubscriberBot();\n const { data: agent, isLoading, isError, refetch } = useAgent(id);\n const setAgentStatus = useSetAgentStatus();\n const [actionError, setActionError] = useState<string | null>(null);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Agent\">\n <LoadingView label=\"Loading agent…\" />\n </PageLayout>\n );\n }\n\n if (isError) {\n return (\n <PageLayout title=\"Agent\">\n <ErrorView message=\"Could not load this agent.\" onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n if (!agent) {\n return (\n <PageLayout title=\"Agent\">\n <EmptyState\n illustration=\"empty-data\"\n title=\"Agent not found\"\n description=\"It may have been removed, or you may not have access to it.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/agents')}\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 Back to agents\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n const a = agent;\n\n return (\n <PageLayout\n title={a.name}\n description={`${formatEnumLabel(a.kind)} agent`}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/agents')}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n }\n >\n <div className=\"flex flex-wrap items-center gap-3\">\n <span className=\"flex size-10 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <Bot className=\"h-5 w-5\" />\n </span>\n <StatusBadge status={a.status} />\n <span className=\"text-sm text-text-secondary\">\n {a.lastRunAt ? `Last run ${formatRelativeTime(a.lastRunAt)}` : 'Never run'}\n </span>\n </div>\n\n {a.description && (\n <p className=\"mt-4 max-w-3xl text-sm text-text-secondary\">{a.description}</p>\n )}\n\n {actionError && (\n <div className=\"mt-4 rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {actionError}\n </div>\n )}\n\n {/* Posture control */}\n <div className=\"mt-6 max-w-sm\">\n <label\n htmlFor=\"agent-posture\"\n className=\"mb-1 block text-xs font-medium text-text-secondary\"\n >\n Operating posture\n </label>\n <select\n id=\"agent-posture\"\n value={a.status}\n disabled={setAgentStatus.isPending}\n onChange={(e) => {\n setActionError(null);\n setAgentStatus.mutate(\n { id: a.id, status: e.target.value as SubAgentStatus },\n {\n onError: (err) =>\n setActionError(err instanceof Error ? err.message : 'Could not change posture.'),\n }\n );\n }}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm 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 <p className=\"mt-1.5 text-xs text-text-secondary\">\n Disabled never acts; Suggest-only proposes; Autonomous acts within its policies.\n </p>\n </div>\n\n {/* Policies */}\n <Section title=\"Policies\" description=\"The autonomous rules that bound this agent\">\n {!a.policies || a.policies.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No policies\"\n description=\"Policies define what this agent may do autonomously, and what it must alert on.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {a.policies.map((policy) => (\n <GlassCard key={policy.id} treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <p className=\"text-sm font-medium text-text-primary\">{policy.name}</p>\n <StatusBadge status={policy.isEnabled ? 'ACTIVE' : 'DISABLED'} />\n </div>\n <p className=\"mt-1 flex items-center gap-1.5 text-xs text-text-secondary\">\n <ShieldCheck className=\"h-3.5 w-3.5\" /> Action: {formatEnumLabel(policy.action)}\n </p>\n {policy.description && (\n <p className=\"mt-2 text-xs text-text-secondary\">{policy.description}</p>\n )}\n <p className=\"mt-2 text-xs text-text-secondary\">\n Triggered {policy.triggerCount}×\n {policy.lastTriggeredAt\n ? ` · last ${formatRelativeTime(policy.lastTriggeredAt)}`\n : ''}\n </p>\n </GlassCard>\n ))}\n </div>\n )}\n </Section>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAqBA,IAAM,IAAmC;CAAC;CAAY;CAAgB;CAAa;AAEnF,SAAgB,IAAkB;CAChC,IAAM,EAAE,UAAO,GAA2B,EACpC,EAAE,kBAAe,GAAkB,EACnC,EAAE,MAAM,GAAO,cAAW,YAAS,eAAY,EAAS,EAAG,EAC3D,IAAiB,GAAmB,EACpC,CAAC,GAAa,KAAkB,EAAwB,KAAK;AAEnE,KAAI,EACF,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD,EAAa,OAAM,kBAAmB,CAAA;EAC3B,CAAA;AAIjB,KAAI,EACF,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GAAW,SAAQ;GAA6B,eAAe,KAAK,GAAS;GAAI,CAAA;EACtE,CAAA;AAIjB,KAAI,CAAC,EACH,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,UAAU;IACpC,WAAU;cACX;IAEQ,CAAA;GAEX,CAAA;EACS,CAAA;CAIjB,IAAM,IAAI;AAEV,QACE,kBAAC,GAAD;EACE,OAAO,EAAE;EACT,aAAa,GAAG,EAAgB,EAAE,KAAK,CAAC;EACxC,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,UAAU;GACpC,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAAA,QAC1B;;YAVb;GAaE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,QAAD;MAAM,WAAU;gBACd,kBAAC,GAAD,EAAK,WAAU,WAAY,CAAA;MACtB,CAAA;KACP,kBAAC,GAAD,EAAa,QAAQ,EAAE,QAAU,CAAA;KACjC,kBAAC,QAAD;MAAM,WAAU;gBACb,EAAE,YAAY,YAAY,EAAmB,EAAE,UAAU,KAAK;MAC1D,CAAA;KACH;;GAEL,EAAE,eACD,kBAAC,KAAD;IAAG,WAAU;cAA8C,EAAE;IAAgB,CAAA;GAG9E,KACC,kBAAC,OAAD;IAAK,WAAU;cACZ;IACG,CAAA;GAIR,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,SAAD;MACE,SAAQ;MACR,WAAU;gBACX;MAEO,CAAA;KACR,kBAAC,UAAD;MACE,IAAG;MACH,OAAO,EAAE;MACT,UAAU,EAAe;MACzB,WAAW,MAAM;AAEf,OADA,EAAe,KAAK,EACpB,EAAe,OACb;QAAE,IAAI,EAAE;QAAI,QAAQ,EAAE,OAAO;QAAyB,EACtD,EACE,UAAU,MACR,EAAe,aAAe,QAAQ,EAAI,UAAU,4BAA4B,EACnF,CACF;;MAEH,WAAU;gBAET,EAAe,KAAK,MACnB,kBAAC,UAAD;OAAgB,OAAO;iBACpB,EAAgB,EAAE;OACZ,EAFI,EAEJ,CACT;MACK,CAAA;KACT,kBAAC,KAAD;MAAG,WAAU;gBAAqC;MAE9C,CAAA;KACA;;GAGN,kBAAC,GAAD;IAAS,OAAM;IAAW,aAAY;cACnC,CAAC,EAAE,YAAY,EAAE,SAAS,WAAW,IACpC,kBAAC,GAAD;KACE,cAAa;KACb,OAAM;KACN,aAAY;KACZ,CAAA,GAEF,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAE,SAAS,KAAK,MACf,kBAAC,GAAD;MAA2B,WAAU;MAAS,WAAU;gBAAxD;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAyC,EAAO;SAAS,CAAA,EACtE,kBAAC,GAAD,EAAa,QAAQ,EAAO,YAAY,WAAW,YAAc,CAAA,CAC7D;;OACN,kBAAC,KAAD;QAAG,WAAU;kBAAb;SACE,kBAAC,GAAD,EAAa,WAAU,eAAgB,CAAA;;SAAU,EAAgB,EAAO,OAAO;SAC7E;;OACH,EAAO,eACN,kBAAC,KAAD;QAAG,WAAU;kBAAoC,EAAO;QAAgB,CAAA;OAE1E,kBAAC,KAAD;QAAG,WAAU;kBAAb;SAAgD;SACnC,EAAO;SAAa;SAC9B,EAAO,kBACJ,WAAW,EAAmB,EAAO,gBAAgB,KACrD;SACF;;OACM;QAjBI,EAAO,GAiBX,CACZ;KACE,CAAA;IAEA,CAAA;GACC"}
1
+ {"version":3,"file":"AgentDetailPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/agents/AgentDetailPage.tsx"],"sourcesContent":["/**\n * Agent detail\n * @module subscriberbot/pages/agents\n *\n * A single AI agent: its kind, posture, last run, and the autonomous policies\n * that bound it. Reads `subAgent(id)`; changes posture via `subSetAgentStatus`.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Bot, ShieldCheck, Plus } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { Modal } from '../../components/Modal';\nimport { LoadingView, ErrorView, Section } from '../../components/StateViews';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { useAgent, useSetAgentStatus, useCreatePolicy } from '../../hooks/useSubscriberBotApi';\nimport { formatEnumLabel, formatRelativeTime } from '../../utils/formatters';\nimport type { SubAgentStatus, SubPolicyAction } from '../../types';\n\nconst STATUS_OPTIONS: SubAgentStatus[] = ['DISABLED', 'SUGGEST_ONLY', 'AUTONOMOUS'];\n\nconst POLICY_ACTIONS: SubPolicyAction[] = [\n 'ALERT',\n 'CREATE_TASK',\n 'RENEW',\n 'CANCEL',\n 'PAUSE',\n 'UPGRADE',\n 'DOWNGRADE',\n];\n\nconst inputCls =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\nconst labelCls = 'mb-1 block text-xs font-medium text-text-secondary';\n\n// ---------------------------------------------------------------------------\n// Add policy modal → subCreatePolicy\n// ---------------------------------------------------------------------------\n\nfunction AddPolicyModal({ agentId, onClose }: { agentId: string; onClose: () => void }) {\n const create = useCreatePolicy();\n const [name, setName] = useState('');\n const [action, setAction] = useState<SubPolicyAction>('ALERT');\n const [description, setDescription] = useState('');\n const [condition, setCondition] = useState('');\n const [isEnabled, setIsEnabled] = useState(true);\n const [formError, setFormError] = useState<string | null>(null);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n if (!name.trim()) {\n setFormError('A policy name is required.');\n return;\n }\n let parsedCondition: Record<string, unknown> | undefined;\n if (condition.trim()) {\n try {\n parsedCondition = JSON.parse(condition) as Record<string, unknown>;\n } catch {\n setFormError('Condition must be valid JSON (e.g. {\"amountOver\": 100}).');\n return;\n }\n }\n create.mutate(\n {\n agentId,\n name: name.trim(),\n action,\n isEnabled,\n ...(description.trim() ? { description: description.trim() } : {}),\n ...(parsedCondition ? { condition: parsedCondition } : {}),\n },\n {\n onSuccess: () => onClose(),\n onError: (err) =>\n setFormError(err instanceof Error ? err.message : 'Could not add policy.'),\n }\n );\n };\n\n return (\n <Modal title=\"Add policy\" onClose={onClose} maxWidthClassName=\"max-w-xl\">\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n {formError && (\n <div className=\"rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {formError}\n </div>\n )}\n <div>\n <label htmlFor=\"policy-name\" className={labelCls}>\n Name <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"policy-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Alert on price hike over 20%\"\n className={inputCls}\n required\n />\n </div>\n <div>\n <label htmlFor=\"policy-action\" className={labelCls}>\n Action\n </label>\n <select\n id=\"policy-action\"\n value={action}\n onChange={(e) => setAction(e.target.value as SubPolicyAction)}\n className={inputCls}\n >\n {POLICY_ACTIONS.map((a) => (\n <option key={a} value={a}>\n {a.replace(/_/g, ' ')}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"policy-condition\" className={labelCls}>\n Condition <span className=\"text-text-secondary\">(optional JSON)</span>\n </label>\n <textarea\n id=\"policy-condition\"\n value={condition}\n onChange={(e) => setCondition(e.target.value)}\n rows={3}\n placeholder={'{ \"priceIncreasePct\": 20 }'}\n className={`${inputCls} font-mono`}\n />\n </div>\n <div>\n <label htmlFor=\"policy-desc\" className={labelCls}>\n Description\n </label>\n <textarea\n id=\"policy-desc\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n className={inputCls}\n />\n </div>\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={isEnabled}\n onChange={(e) => setIsEnabled(e.target.checked)}\n className=\"size-4 rounded border-border-subtle\"\n />\n Enabled\n </label>\n <div className=\"flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {create.isPending ? 'Adding…' : 'Add policy'}\n </button>\n </div>\n </form>\n </Modal>\n );\n}\n\nexport function AgentDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useSubscriberBot();\n const { data: agent, isLoading, isError, refetch } = useAgent(id);\n const setAgentStatus = useSetAgentStatus();\n const [actionError, setActionError] = useState<string | null>(null);\n const [showAddPolicy, setShowAddPolicy] = useState(false);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Agent\">\n <LoadingView label=\"Loading agent…\" />\n </PageLayout>\n );\n }\n\n if (isError) {\n return (\n <PageLayout title=\"Agent\">\n <ErrorView message=\"Could not load this agent.\" onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n if (!agent) {\n return (\n <PageLayout title=\"Agent\">\n <EmptyState\n illustration=\"empty-data\"\n title=\"Agent not found\"\n description=\"It may have been removed, or you may not have access to it.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/agents')}\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 Back to agents\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n const a = agent;\n\n return (\n <PageLayout\n title={a.name}\n description={`${formatEnumLabel(a.kind)} agent`}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/agents')}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n }\n >\n <div className=\"flex flex-wrap items-center gap-3\">\n <span className=\"flex size-10 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <Bot className=\"h-5 w-5\" />\n </span>\n <StatusBadge status={a.status} />\n <span className=\"text-sm text-text-secondary\">\n {a.lastRunAt ? `Last run ${formatRelativeTime(a.lastRunAt)}` : 'Never run'}\n </span>\n </div>\n\n {a.description && (\n <p className=\"mt-4 max-w-3xl text-sm text-text-secondary\">{a.description}</p>\n )}\n\n {actionError && (\n <div className=\"mt-4 rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {actionError}\n </div>\n )}\n\n {/* Posture control */}\n <div className=\"mt-6 max-w-sm\">\n <label\n htmlFor=\"agent-posture\"\n className=\"mb-1 block text-xs font-medium text-text-secondary\"\n >\n Operating posture\n </label>\n <select\n id=\"agent-posture\"\n value={a.status}\n disabled={setAgentStatus.isPending}\n onChange={(e) => {\n setActionError(null);\n setAgentStatus.mutate(\n { id: a.id, status: e.target.value as SubAgentStatus },\n {\n onError: (err) =>\n setActionError(err instanceof Error ? err.message : 'Could not change posture.'),\n }\n );\n }}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm 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 <p className=\"mt-1.5 text-xs text-text-secondary\">\n Disabled never acts; Suggest-only proposes; Autonomous acts within its policies.\n </p>\n </div>\n\n {/* Policies */}\n <Section\n title=\"Policies\"\n description=\"The autonomous rules that bound this agent\"\n action={\n <button\n type=\"button\"\n onClick={() => setShowAddPolicy(true)}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken\"\n >\n <Plus className=\"h-3.5 w-3.5\" /> Add policy\n </button>\n }\n >\n {!a.policies || a.policies.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No policies\"\n description=\"Policies define what this agent may do autonomously, and what it must alert on.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {a.policies.map((policy) => (\n <GlassCard key={policy.id} treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <p className=\"text-sm font-medium text-text-primary\">{policy.name}</p>\n <StatusBadge status={policy.isEnabled ? 'ACTIVE' : 'DISABLED'} />\n </div>\n <p className=\"mt-1 flex items-center gap-1.5 text-xs text-text-secondary\">\n <ShieldCheck className=\"h-3.5 w-3.5\" /> Action: {formatEnumLabel(policy.action)}\n </p>\n {policy.description && (\n <p className=\"mt-2 text-xs text-text-secondary\">{policy.description}</p>\n )}\n <p className=\"mt-2 text-xs text-text-secondary\">\n Triggered {policy.triggerCount}×\n {policy.lastTriggeredAt\n ? ` · last ${formatRelativeTime(policy.lastTriggeredAt)}`\n : ''}\n </p>\n </GlassCard>\n ))}\n </div>\n )}\n </Section>\n\n {showAddPolicy && <AddPolicyModal agentId={a.id} onClose={() => setShowAddPolicy(false)} />}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -78,6 +78,7 @@ function v() {
78
78
  /* @__PURE__ */ m("div", {
79
79
  className: "flex flex-wrap items-center gap-3",
80
80
  children: [/* @__PURE__ */ p("select", {
81
+ "aria-label": "Filter by kind",
81
82
  value: y,
82
83
  onChange: (e) => b(e.target.value),
83
84
  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)]",
@@ -86,6 +87,7 @@ function v() {
86
87
  children: e.label
87
88
  }, e.value))
88
89
  }), /* @__PURE__ */ m("select", {
90
+ "aria-label": "Filter by posture",
89
91
  value: x,
90
92
  onChange: (e) => S(e.target.value),
91
93
  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)]",
@@ -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 { Plus, Bot } from 'lucide-react';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\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\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 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 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 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 <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {agents.map((a) => (\n <div\n key={a.id}\n className=\"flex flex-col rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <button\n type=\"button\"\n onClick={() => navigateTo(`/agents/${a.id}`)}\n className=\"text-left\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"flex size-9 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <Bot className=\"h-4 w-4\" />\n </span>\n <StatusBadge status={a.status} />\n </div>\n <p className=\"mt-3 truncate text-sm font-semibold text-text-primary\">{a.name}</p>\n <p className=\"text-xs text-text-secondary\">{formatEnumLabel(a.kind)} agent</p>\n {a.description && (\n <p className=\"mt-2 line-clamp-2 text-xs text-text-secondary\">{a.description}</p>\n )}\n <p className=\"mt-2 text-xs text-text-secondary\">\n {a.lastRunAt ? `Last run ${formatRelativeTime(a.lastRunAt)}` : 'Never run'}\n </p>\n </button>\n <div className=\"mt-3 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 value={a.status}\n disabled={setAgentStatus.isPending}\n onChange={(e) =>\n setAgentStatus.mutate({ id: a.id, status: e.target.value as SubAgentStatus })\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 </div>\n ))}\n </div>\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 { Plus, Bot } from 'lucide-react';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\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\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 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 <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {agents.map((a) => (\n <div\n key={a.id}\n className=\"flex flex-col rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <button\n type=\"button\"\n onClick={() => navigateTo(`/agents/${a.id}`)}\n className=\"text-left\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"flex size-9 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <Bot className=\"h-4 w-4\" />\n </span>\n <StatusBadge status={a.status} />\n </div>\n <p className=\"mt-3 truncate text-sm font-semibold text-text-primary\">{a.name}</p>\n <p className=\"text-xs text-text-secondary\">{formatEnumLabel(a.kind)} agent</p>\n {a.description && (\n <p className=\"mt-2 line-clamp-2 text-xs text-text-secondary\">{a.description}</p>\n )}\n <p className=\"mt-2 text-xs text-text-secondary\">\n {a.lastRunAt ? `Last run ${formatRelativeTime(a.lastRunAt)}` : 'Never run'}\n </p>\n </button>\n <div className=\"mt-3 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 value={a.status}\n disabled={setAgentStatus.isPending}\n onChange={(e) =>\n setAgentStatus.mutate({ id: a.id, status: e.target.value as SubAgentStatus })\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 </div>\n ))}\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}