@burdenoff/microfe-vibecontrols 2026.1011.1 → 2026.1013.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.
@@ -0,0 +1,19 @@
1
+ import { useTr as e } from "../../shared/hooks/useTr.js";
2
+ import { ConfirmDialog as t } from "../shared/ConfirmDialog.js";
3
+ import { jsx as n } from "react/jsx-runtime";
4
+ //#region src/components/agents/CheckSessionHealthDialog.tsx
5
+ function r({ isOpen: r, onClose: i, onConfirm: a, isLoading: o = !1, message: s }) {
6
+ let c = e();
7
+ return /* @__PURE__ */ n(t, {
8
+ isOpen: r,
9
+ onClose: i,
10
+ onConfirm: a,
11
+ title: c("agentDetails.checkSessionHealthTitle", "Check session health?"),
12
+ message: s ?? c("agentDetails.checkSessionHealthMessage", "This checks every running session in the whole workspace, not only this agent’s. Any session whose agent reports it dead or cannot be reached is marked stopped, including sessions that belong to other agents."),
13
+ confirmLabel: c("agentDetails.checkSessionHealthConfirm", "Check all sessions"),
14
+ variant: "warning",
15
+ isLoading: o
16
+ });
17
+ }
18
+ //#endregion
19
+ export { r as CheckSessionHealthDialog };
@@ -1,281 +1,271 @@
1
- import { useSetupAgentGatewayAuthMutation as e, useUpdateAgentMutation as t } from "../../generated/wspace-operations.js";
2
- import { useTr as n } from "../../shared/hooks/useTr.js";
3
- import { ConfirmDialog as r } from "../shared/ConfirmDialog.js";
4
- import { Card as i } from "../shared/Card.js";
1
+ import { useUpdateAgentMutation as e } from "../../generated/wspace-operations.js";
2
+ import { useTr as t } from "../../shared/hooks/useTr.js";
3
+ import { ConfirmDialog as n } from "../shared/ConfirmDialog.js";
4
+ import { Card as r } from "../shared/Card.js";
5
5
  import "../shared/index.js";
6
- import { isNative as a, nativeCopyText as o, nativeToast as s } from "../../utils/nativeBridge.js";
7
- import { useState as c } from "react";
8
- import { Check as l, Copy as u, Eye as d, EyeOff as f, Link2 as p, Loader2 as m, Monitor as h, RefreshCw as g, Shield as _, Unlink as v, X as y } from "lucide-react";
9
- import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
10
- import { Button as C } from "@burdenoff/fe-libs/ui";
6
+ import { isNative as i, nativeCopyText as a, nativeToast as o } from "../../utils/nativeBridge.js";
7
+ import { notify as s } from "../../lib/toast.js";
8
+ import { VIBE_PERMISSIONS as c } from "../../constants/permissions.js";
9
+ import { useRepairGatewayAuth as l } from "../../hooks/useRepairGatewayAuth.js";
10
+ import { OneTimeSecretPanel as u } from "./OneTimeSecretPanel.js";
11
+ import { RepairGatewayAuthDialog as d } from "./RepairGatewayAuthDialog.js";
12
+ import { useState as f } from "react";
13
+ import { Check as p, Copy as m, Link2 as h, Loader2 as g, Monitor as _, RefreshCw as v, Shield as y, Unlink as b, X as x } from "lucide-react";
14
+ import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
15
+ import { Button as T } from "@burdenoff/fe-libs/ui";
16
+ import { PermissionButton as E } from "@burdenoff/fe-libs/shared/components";
11
17
  //#region src/components/agents/GatewayAuthCard.tsx
12
- function w({ agent: w, onUpdate: T }) {
13
- let E = n(), [D] = t(), [O] = e(), [k, A] = c(!1), [j, M] = c(null), [N, P] = c(!1), [F, I] = c(null), [L, R] = c(!1), [z, B] = c(!1), [V, H] = c(!1), [U, W] = c(!1), G = !!(w.appId && w.appClientId), K = w.metadata?.devportalApplicationId, q = async () => {
14
- A(!0), M(null);
18
+ function D({ agent: D, onUpdate: O }) {
19
+ let k = t(), [A] = e(), { repair: j, running: M, rotationEpoch: N } = l(D.id), [P, F] = f(!1), [I, L] = f(null), [R, z] = f(null), B = R && R.epoch === N ? R : null, [V, H] = f(!1), [U, W] = f(!1), [G, K] = f(!1), [q, J] = f(!1), Y = !!(D.appId && D.appClientId), X = D.metadata?.devportalApplicationId, Z = async () => {
20
+ F(!0), L(null);
15
21
  try {
16
- let { data: e } = await O({ variables: { input: { agentId: w.id } } }), t = e?.setupAgentGatewayAuth;
17
- if (!t) throw Error(E("agentDetails.gatewayAuthNoResultError", "No result returned from setupAgentGatewayAuth"));
18
- I(t.clientSecret), t.error && M(t.error), T();
19
- } catch (e) {
20
- M(e instanceof Error ? e.message : E("agentDetails.failedSetupGatewayAuth", "Failed to set up gateway auth"));
22
+ let e = await j();
23
+ if (e.status === "busy") {
24
+ L(k("agentDetails.repairAlreadyRunning", "A repair for this agent is already running. Wait for it to finish."));
25
+ return;
26
+ }
27
+ if (e.status === "failed") {
28
+ L(e.message || k("agentDetails.failedSetupGatewayAuth", "Failed to set up gateway auth"));
29
+ return;
30
+ }
31
+ if (e.status === "unchanged") {
32
+ s.info(k("agentDetails.repairUnchanged", "Nothing was changed: a credential push for this agent is already in progress or has just completed.")), O();
33
+ return;
34
+ }
35
+ z({
36
+ value: e.clientSecret,
37
+ delivered: e.status === "ok",
38
+ epoch: e.epoch
39
+ }), e.status === "delivery-failed" && L(e.error), O();
21
40
  } finally {
22
- A(!1);
41
+ F(!1);
23
42
  }
24
- }, J = async () => {
25
- H(!0), M(null);
43
+ }, Q = async () => {
44
+ W(!0), L(null);
26
45
  try {
27
- await D({ variables: {
28
- id: w.id,
46
+ await A({ variables: {
47
+ id: D.id,
29
48
  input: {
30
49
  appId: null,
31
50
  appClientId: null
32
51
  }
33
- } }), I(null), W(!1), T();
52
+ } }), z(null), K(!1), O();
34
53
  } catch (e) {
35
- W(!1), M(e instanceof Error ? e.message : E("agentDetails.failedUnlinkApp", "Failed to unlink app"));
54
+ K(!1), L(e instanceof Error ? e.message : k("agentDetails.failedUnlinkApp", "Failed to unlink app"));
36
55
  } finally {
37
- H(!1);
56
+ W(!1);
38
57
  }
39
58
  };
40
- return /* @__PURE__ */ S(i, {
59
+ return /* @__PURE__ */ w(r, {
41
60
  padding: "none",
42
61
  children: [
43
- /* @__PURE__ */ x("div", {
62
+ /* @__PURE__ */ C("div", {
44
63
  className: "p-4 border-b border-border-default",
45
- children: /* @__PURE__ */ S("h3", {
64
+ children: /* @__PURE__ */ w("h3", {
46
65
  className: "font-semibold text-text-primary flex items-center gap-2",
47
- children: [/* @__PURE__ */ x(_, {
66
+ children: [/* @__PURE__ */ C(y, {
48
67
  className: "size-5",
49
68
  "aria-hidden": "true"
50
- }), E("agentDetails.gatewayAuthTitle", "Gateway Auth (OAuth2)")]
69
+ }), k("agentDetails.gatewayAuthTitle", "Gateway Auth (OAuth2)")]
51
70
  })
52
71
  }),
53
- /* @__PURE__ */ S("div", {
72
+ /* @__PURE__ */ w("div", {
54
73
  className: "p-4 space-y-3",
55
- children: [j && /* @__PURE__ */ S("div", {
74
+ children: [I && /* @__PURE__ */ w("div", {
56
75
  role: "alert",
57
76
  className: "flex items-center gap-2 p-3 bg-status-error-bg-subtle border border-status-error-border text-status-error-text rounded-md text-sm",
58
77
  children: [
59
- /* @__PURE__ */ x(y, {
78
+ /* @__PURE__ */ C(x, {
60
79
  className: "size-4 flex-shrink-0",
61
80
  "aria-hidden": "true"
62
81
  }),
63
- /* @__PURE__ */ x("span", {
82
+ /* @__PURE__ */ C("span", {
64
83
  className: "flex-1 min-w-0 break-words",
65
- children: j
84
+ children: I
66
85
  }),
67
- /* @__PURE__ */ x("button", {
86
+ /* @__PURE__ */ C("button", {
68
87
  type: "button",
69
- onClick: () => M(null),
70
- "aria-label": E("agentDetails.dismissError", "Dismiss error"),
88
+ onClick: () => L(null),
89
+ "aria-label": k("agentDetails.dismissError", "Dismiss error"),
71
90
  className: "flex-shrink-0 p-0.5 hover:bg-status-error-border/40 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
72
- children: /* @__PURE__ */ x(y, {
91
+ children: /* @__PURE__ */ C(x, {
73
92
  className: "size-3.5",
74
93
  "aria-hidden": "true"
75
94
  })
76
95
  })
77
96
  ]
78
- }), G ? /* @__PURE__ */ S(b, { children: [
79
- /* @__PURE__ */ S("div", {
97
+ }), Y ? /* @__PURE__ */ w(S, { children: [
98
+ /* @__PURE__ */ w("div", {
80
99
  className: "flex items-start gap-3",
81
- children: [/* @__PURE__ */ x("div", {
100
+ children: [/* @__PURE__ */ C("div", {
82
101
  className: "size-8 rounded-lg bg-status-success-bg-subtle flex items-center justify-center flex-shrink-0 mt-0.5",
83
- children: /* @__PURE__ */ x(p, {
102
+ children: /* @__PURE__ */ C(h, {
84
103
  className: "size-4 text-status-success-text",
85
104
  "aria-hidden": "true"
86
105
  })
87
- }), /* @__PURE__ */ S("div", {
106
+ }), /* @__PURE__ */ w("div", {
88
107
  className: "flex-1 min-w-0 space-y-2",
89
- children: [/* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("p", {
108
+ children: [/* @__PURE__ */ w("div", { children: [/* @__PURE__ */ C("p", {
90
109
  className: "text-sm font-medium text-text-primary",
91
- children: E("agentDetails.linkedToOauthApp", "Linked to OAuth App")
92
- }), /* @__PURE__ */ x("p", {
110
+ children: k("agentDetails.linkedToOauthApp", "Linked to OAuth App")
111
+ }), /* @__PURE__ */ C("p", {
93
112
  className: "text-xs text-text-muted",
94
- children: E("agentDetails.gatewayAuthLinkedDescription", "This agent can authenticate with the API gateway using Client Credentials.")
95
- })] }), /* @__PURE__ */ S("div", {
113
+ children: k("agentDetails.gatewayAuthLinkedDescription", "This agent can authenticate with the API gateway using Client Credentials.")
114
+ })] }), /* @__PURE__ */ w("div", {
96
115
  className: "grid grid-cols-1 sm:grid-cols-2 gap-3",
97
- children: [/* @__PURE__ */ S("div", {
116
+ children: [/* @__PURE__ */ w("div", {
98
117
  className: "min-w-0",
99
- children: [/* @__PURE__ */ x("p", {
118
+ children: [/* @__PURE__ */ C("p", {
100
119
  className: "text-xs text-text-secondary mb-1",
101
- children: E("agentDetails.clientId", "Client ID")
102
- }), /* @__PURE__ */ S("div", {
120
+ children: k("agentDetails.clientId", "Client ID")
121
+ }), /* @__PURE__ */ w("div", {
103
122
  className: "flex items-center gap-2",
104
- children: [/* @__PURE__ */ x("code", {
123
+ children: [/* @__PURE__ */ C("code", {
105
124
  className: "text-xs font-mono text-text-primary bg-bg-sunken px-2 py-1 rounded truncate block flex-1 min-w-0",
106
- children: w.appClientId
107
- }), /* @__PURE__ */ x("button", {
125
+ children: D.appClientId
126
+ }), /* @__PURE__ */ C("button", {
108
127
  type: "button",
109
128
  onClick: async () => {
110
- if (w.appClientId) try {
111
- await o(w.appClientId), a() && s("Copied"), B(!0), setTimeout(() => B(!1), 2e3);
129
+ if (D.appClientId) try {
130
+ await a(D.appClientId), i() && o("Copied"), H(!0), setTimeout(() => H(!1), 2e3);
112
131
  } catch {}
113
132
  },
114
- "aria-label": E("agentDetails.copyClientId", "Copy Client ID"),
115
- title: E("agentDetails.copyClientId", "Copy Client ID"),
133
+ "aria-label": k("agentDetails.copyClientId", "Copy Client ID"),
134
+ title: k("agentDetails.copyClientId", "Copy Client ID"),
116
135
  className: "p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
117
- children: z ? /* @__PURE__ */ x(l, {
136
+ children: V ? /* @__PURE__ */ C(p, {
118
137
  className: "size-3.5 text-status-success-text",
119
138
  "aria-hidden": "true"
120
- }) : /* @__PURE__ */ x(u, {
139
+ }) : /* @__PURE__ */ C(m, {
121
140
  className: "size-3.5 text-text-secondary",
122
141
  "aria-hidden": "true"
123
142
  })
124
143
  })]
125
144
  })]
126
- }), /* @__PURE__ */ S("div", {
145
+ }), /* @__PURE__ */ w("div", {
127
146
  className: "min-w-0",
128
- children: [/* @__PURE__ */ x("p", {
147
+ children: [/* @__PURE__ */ C("p", {
129
148
  className: "text-xs text-text-secondary mb-1",
130
- children: E("agentDetails.appId", "App ID")
131
- }), /* @__PURE__ */ x("code", {
149
+ children: k("agentDetails.appId", "App ID")
150
+ }), /* @__PURE__ */ C("code", {
132
151
  className: "text-xs font-mono text-text-muted bg-bg-sunken px-2 py-1 rounded truncate block",
133
- children: w.appId
152
+ children: D.appId
134
153
  })]
135
154
  })]
136
155
  })]
137
156
  })]
138
157
  }),
139
- F && /* @__PURE__ */ S("div", {
140
- className: "p-3 bg-status-warning-bg-subtle border border-status-warning-border rounded-card space-y-2",
141
- children: [
142
- /* @__PURE__ */ x("p", {
143
- className: "text-sm font-medium text-status-warning-text",
144
- children: E("agentDetails.clientSecretOneTimeTitle", "Client Secret (one-time display)")
145
- }),
146
- /* @__PURE__ */ x("p", {
147
- className: "text-xs text-text-secondary",
148
- children: E("agentDetails.clientSecretOneTimeDescription", "This secret has been automatically sent to the agent. Save it now if you need it — it won't be shown again.")
149
- }),
150
- /* @__PURE__ */ S("div", {
151
- className: "flex items-center gap-2",
152
- children: [
153
- /* @__PURE__ */ x("code", {
154
- className: "text-xs font-mono text-text-primary bg-bg-sunken px-2 py-1 rounded flex-1 min-w-0 truncate",
155
- children: N ? F : "•".repeat(32)
156
- }),
157
- /* @__PURE__ */ x("button", {
158
- type: "button",
159
- onClick: () => P(!N),
160
- "aria-label": N ? E("agentDetails.hideClientSecret", "Hide client secret") : E("agentDetails.showClientSecret", "Show client secret"),
161
- className: "p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
162
- children: x(N ? f : d, {
163
- className: "size-3.5 text-text-secondary",
164
- "aria-hidden": "true"
165
- })
166
- }),
167
- /* @__PURE__ */ x("button", {
168
- type: "button",
169
- onClick: async () => {
170
- if (F) try {
171
- await o(F), a() && s("Secret copied"), R(!0), setTimeout(() => R(!1), 2e3);
172
- } catch {}
173
- },
174
- "aria-label": E("agentDetails.copyClientSecret", "Copy client secret"),
175
- className: "p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
176
- children: L ? /* @__PURE__ */ x(l, {
177
- className: "size-3.5 text-status-success-text",
178
- "aria-hidden": "true"
179
- }) : /* @__PURE__ */ x(u, {
180
- className: "size-3.5 text-text-secondary",
181
- "aria-hidden": "true"
182
- })
183
- })
184
- ]
185
- })
186
- ]
187
- }),
188
- /* @__PURE__ */ S("div", {
158
+ B && /* @__PURE__ */ C(u, {
159
+ secret: B.value,
160
+ description: B.delivered ? void 0 : k("agentDetails.clientSecretNotDelivered", "This secret could not be delivered to the agent, and the previous one no longer works. Save it now and configure the agent with it, or run Repair again once the agent is reachable — it won't be shown again.")
161
+ }, B.epoch),
162
+ /* @__PURE__ */ w("div", {
189
163
  className: "flex flex-wrap items-center gap-2",
190
164
  children: [
191
- K && /* @__PURE__ */ S("a", {
192
- href: `/devportal/apps/${K}`,
165
+ X && /* @__PURE__ */ w("a", {
166
+ href: `/devportal/apps/${X}`,
193
167
  className: "inline-flex items-center gap-2 px-3 py-1.5 text-xs font-medium text-text-primary bg-bg-sunken hover:bg-bg-elevated rounded-button transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
194
- children: [/* @__PURE__ */ x(h, {
168
+ children: [/* @__PURE__ */ C(_, {
195
169
  className: "size-3",
196
170
  "aria-hidden": "true"
197
- }), E("agentDetails.viewInDeveloperPortal", "View in Developer Portal")]
171
+ }), k("agentDetails.viewInDeveloperPortal", "View in Developer Portal")]
198
172
  }),
199
- /* @__PURE__ */ S(C, {
200
- type: "button",
201
- variant: "secondary",
202
- size: "sm",
203
- onClick: () => void q(),
204
- disabled: k,
205
- "aria-busy": k,
206
- title: E("agentDetails.repushCredentialsTitle", "Rotate the OAuth secret and push it to the agent. Use this if the agent shows degraded with \"boot state awaiting-config\"."),
207
- children: [k ? /* @__PURE__ */ x(m, {
208
- className: "size-3 animate-spin",
209
- "aria-hidden": "true"
210
- }) : /* @__PURE__ */ x(g, {
211
- className: "size-3",
212
- "aria-hidden": "true"
213
- }), E("agentDetails.repushCredentials", "Re-push credentials")]
173
+ /* @__PURE__ */ C(E, {
174
+ permission: c.AGENT_UPDATE,
175
+ deniedBehavior: "disable",
176
+ deniedTooltip: k("agentDetails.repushCredentialsDenied", "You don't have permission to update agents"),
177
+ children: /* @__PURE__ */ w(T, {
178
+ type: "button",
179
+ variant: "secondary",
180
+ size: "sm",
181
+ onClick: () => J(!0),
182
+ disabled: P || M,
183
+ "aria-busy": P || M,
184
+ title: k("agentDetails.repushCredentialsTitle", "Rotate the OAuth secret and push it to the agent. Use this if the agent shows degraded with \"boot state awaiting-config\"."),
185
+ children: [P ? /* @__PURE__ */ C(g, {
186
+ className: "size-3 animate-spin",
187
+ "aria-hidden": "true"
188
+ }) : /* @__PURE__ */ C(v, {
189
+ className: "size-3",
190
+ "aria-hidden": "true"
191
+ }), k("agentDetails.repushCredentials", "Re-push credentials")]
192
+ })
214
193
  }),
215
- /* @__PURE__ */ S(C, {
194
+ /* @__PURE__ */ w(T, {
216
195
  type: "button",
217
196
  variant: "ghost",
218
197
  size: "sm",
219
- onClick: () => W(!0),
220
- disabled: V,
221
- "aria-busy": V,
198
+ onClick: () => K(!0),
199
+ disabled: U,
200
+ "aria-busy": U,
222
201
  className: "text-status-error-text hover:bg-status-error-bg-subtle hover:text-status-error-text",
223
- children: [V ? /* @__PURE__ */ x(m, {
202
+ children: [U ? /* @__PURE__ */ C(g, {
224
203
  className: "size-3 animate-spin",
225
204
  "aria-hidden": "true"
226
- }) : /* @__PURE__ */ x(v, {
205
+ }) : /* @__PURE__ */ C(b, {
227
206
  className: "size-3",
228
207
  "aria-hidden": "true"
229
- }), E("agentDetails.unlinkApp", "Unlink App")]
208
+ }), k("agentDetails.unlinkApp", "Unlink App")]
230
209
  })
231
210
  ]
232
211
  })
233
- ] }) : /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ S("div", {
212
+ ] }) : /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ w("div", {
234
213
  className: "flex items-start gap-3",
235
- children: [/* @__PURE__ */ x("div", {
214
+ children: [/* @__PURE__ */ C("div", {
236
215
  className: "size-8 rounded-lg bg-bg-sunken flex items-center justify-center flex-shrink-0 mt-0.5",
237
- children: /* @__PURE__ */ x(_, {
216
+ children: /* @__PURE__ */ C(y, {
238
217
  className: "size-4 text-text-muted",
239
218
  "aria-hidden": "true"
240
219
  })
241
- }), /* @__PURE__ */ S("div", {
220
+ }), /* @__PURE__ */ w("div", {
242
221
  className: "flex-1 min-w-0",
243
- children: [/* @__PURE__ */ x("p", {
222
+ children: [/* @__PURE__ */ C("p", {
244
223
  className: "text-sm font-medium text-text-primary",
245
- children: E("agentDetails.noOauthAppLinked", "No OAuth App Linked")
246
- }), /* @__PURE__ */ x("p", {
224
+ children: k("agentDetails.noOauthAppLinked", "No OAuth App Linked")
225
+ }), /* @__PURE__ */ C("p", {
247
226
  className: "text-xs text-text-muted mt-0.5",
248
- children: E("agentDetails.gatewayAuthSetupDescription", "Set up gateway auth to allow this agent to communicate with the API gateways using OAuth2 Client Credentials. This creates an OAuth app, registers it in the Developer Portal, and pushes the credentials to the agent.")
227
+ children: k("agentDetails.gatewayAuthSetupDescription", "Set up gateway auth to allow this agent to communicate with the API gateways using OAuth2 Client Credentials. This creates an OAuth app, registers it in the Developer Portal, and pushes the credentials to the agent.")
249
228
  })]
250
229
  })]
251
- }), /* @__PURE__ */ x(C, {
230
+ }), /* @__PURE__ */ C(T, {
252
231
  type: "button",
253
- onClick: () => void q(),
254
- disabled: k,
255
- "aria-busy": k,
256
- children: k ? /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(m, {
232
+ onClick: () => void Z(),
233
+ disabled: P,
234
+ "aria-busy": P,
235
+ children: P ? /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ C(g, {
257
236
  className: "size-4 animate-spin",
258
237
  "aria-hidden": "true"
259
- }), E("agentDetails.settingUp", "Setting up...")] }) : /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(p, {
238
+ }), k("agentDetails.settingUp", "Setting up...")] }) : /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ C(h, {
260
239
  className: "size-4",
261
240
  "aria-hidden": "true"
262
- }), E("agentDetails.setupGatewayAuth", "Setup Gateway Auth")] })
241
+ }), k("agentDetails.setupGatewayAuth", "Setup Gateway Auth")] })
263
242
  })] })]
264
243
  }),
265
- /* @__PURE__ */ x(r, {
266
- isOpen: U,
244
+ /* @__PURE__ */ C(d, {
245
+ isOpen: q,
246
+ onClose: () => {
247
+ P || J(!1);
248
+ },
249
+ onConfirm: () => {
250
+ Z().finally(() => J(!1));
251
+ },
252
+ agentName: D.name,
253
+ isLoading: P
254
+ }),
255
+ /* @__PURE__ */ C(n, {
256
+ isOpen: G,
267
257
  onClose: () => {
268
- V || W(!1);
258
+ U || K(!1);
269
259
  },
270
- onConfirm: () => void J(),
271
- title: E("agentDetails.unlinkApp", "Unlink App"),
272
- message: E("agentDetails.confirmUnlinkOauthApp", "Remove the linked OAuth app from this agent? The app will still exist in auth-svc."),
273
- confirmLabel: E("agentDetails.unlinkApp", "Unlink App"),
260
+ onConfirm: () => void Q(),
261
+ title: k("agentDetails.unlinkApp", "Unlink App"),
262
+ message: k("agentDetails.confirmUnlinkOauthApp", "Remove the linked OAuth app from this agent? The app will still exist in auth-svc."),
263
+ confirmLabel: k("agentDetails.unlinkApp", "Unlink App"),
274
264
  variant: "danger",
275
- isLoading: V
265
+ isLoading: U
276
266
  })
277
267
  ]
278
268
  });
279
269
  }
280
270
  //#endregion
281
- export { w as GatewayAuthCard };
271
+ export { D as GatewayAuthCard };
@@ -0,0 +1,79 @@
1
+ import { useTr as e } from "../../shared/hooks/useTr.js";
2
+ import { isNative as t, nativeCopyText as n, nativeToast as r } from "../../utils/nativeBridge.js";
3
+ import { notify as i } from "../../lib/toast.js";
4
+ import { useEffect as a, useRef as o, useState as s } from "react";
5
+ import { Check as c, Copy as l, Eye as u, EyeOff as d } from "lucide-react";
6
+ import { jsx as f, jsxs as p } from "react/jsx-runtime";
7
+ import { Button as m } from "@burdenoff/fe-libs/ui";
8
+ //#region src/components/agents/OneTimeSecretPanel.tsx
9
+ function h({ secret: h, description: g, onDismiss: _ }) {
10
+ let v = e(), [y, b] = s(!1), [x, S] = s(!1), C = o(void 0);
11
+ a(() => () => clearTimeout(C.current), []);
12
+ let w = async () => {
13
+ if (!await n(h).catch(() => !1)) {
14
+ i.error(v("agentDetails.copyClientSecretFailed", "The secret could not be copied. Show it and copy it by hand: it will not be shown again."));
15
+ return;
16
+ }
17
+ t() && r("Secret copied"), S(!0), clearTimeout(C.current), C.current = setTimeout(() => S(!1), 2e3);
18
+ };
19
+ return /* @__PURE__ */ p("div", {
20
+ "data-testid": "one-time-secret-panel",
21
+ className: "p-3 bg-status-warning-bg-subtle border border-status-warning-border rounded-card space-y-2",
22
+ children: [
23
+ /* @__PURE__ */ f("p", {
24
+ className: "text-sm font-medium text-status-warning-text",
25
+ children: v("agentDetails.clientSecretOneTimeTitle", "Client Secret (one-time display)")
26
+ }),
27
+ /* @__PURE__ */ f("p", {
28
+ className: "text-xs text-text-secondary",
29
+ children: g ?? v("agentDetails.clientSecretOneTimeDescription", "This secret has been automatically sent to the agent. Save it now if you need it — it won't be shown again.")
30
+ }),
31
+ /* @__PURE__ */ p("div", {
32
+ className: "flex items-center gap-2",
33
+ children: [
34
+ /* @__PURE__ */ f("code", {
35
+ "data-testid": "one-time-secret-value",
36
+ className: "text-xs font-mono text-text-primary bg-bg-sunken px-2 py-1 rounded flex-1 min-w-0 truncate",
37
+ children: y ? h : "•".repeat(32)
38
+ }),
39
+ /* @__PURE__ */ f("button", {
40
+ type: "button",
41
+ onClick: () => b(!y),
42
+ "aria-label": y ? v("agentDetails.hideClientSecret", "Hide client secret") : v("agentDetails.showClientSecret", "Show client secret"),
43
+ className: "p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
44
+ children: f(y ? d : u, {
45
+ className: "size-3.5 text-text-secondary",
46
+ "aria-hidden": "true"
47
+ })
48
+ }),
49
+ /* @__PURE__ */ f("button", {
50
+ type: "button",
51
+ onClick: () => void w(),
52
+ "aria-label": v("agentDetails.copyClientSecret", "Copy client secret"),
53
+ className: "p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
54
+ children: x ? /* @__PURE__ */ f(c, {
55
+ className: "size-3.5 text-status-success-text",
56
+ "aria-hidden": "true"
57
+ }) : /* @__PURE__ */ f(l, {
58
+ className: "size-3.5 text-text-secondary",
59
+ "aria-hidden": "true"
60
+ })
61
+ })
62
+ ]
63
+ }),
64
+ _ && /* @__PURE__ */ f("div", {
65
+ className: "flex justify-end",
66
+ children: /* @__PURE__ */ f(m, {
67
+ type: "button",
68
+ size: "sm",
69
+ variant: "ghost",
70
+ "data-testid": "one-time-secret-dismiss",
71
+ onClick: _,
72
+ children: v("agentDetails.dismissSecret", "Dismiss")
73
+ })
74
+ })
75
+ ]
76
+ });
77
+ }
78
+ //#endregion
79
+ export { h as OneTimeSecretPanel };
@@ -0,0 +1,19 @@
1
+ import { useTr as e } from "../../shared/hooks/useTr.js";
2
+ import { ConfirmDialog as t } from "../shared/ConfirmDialog.js";
3
+ import { jsx as n } from "react/jsx-runtime";
4
+ //#region src/components/agents/RepairGatewayAuthDialog.tsx
5
+ function r({ isOpen: r, onClose: i, onConfirm: a, agentName: o, isLoading: s = !1 }) {
6
+ let c = e();
7
+ return /* @__PURE__ */ n(t, {
8
+ isOpen: r,
9
+ onClose: i,
10
+ onConfirm: a,
11
+ title: c("agentDetails.repairGatewayAuthTitle", "Repair gateway auth?"),
12
+ message: c("agentDetails.repairGatewayAuthMessage", "This rotates the OAuth secret of \"{{name}}\" and pushes a new one to the agent. The current secret stops working immediately, and the OAuth app is re-attributed to you. Only continue if the agent reports that it is waiting for its credentials.", { name: o }),
13
+ confirmLabel: c("agentDetails.repairGatewayAuthConfirm", "Rotate and push"),
14
+ variant: "warning",
15
+ isLoading: s
16
+ });
17
+ }
18
+ //#endregion
19
+ export { r as RepairGatewayAuthDialog };
@@ -4,8 +4,11 @@ import "./RemoteTaskPermissionsCard.js";
4
4
  import "./AgentVisibilityCard.js";
5
5
  import "./AgentList.js";
6
6
  import "./AgentForm.js";
7
+ import "./OneTimeSecretPanel.js";
8
+ import "./RepairGatewayAuthDialog.js";
7
9
  import "./GatewayAuthCard.js";
8
10
  import "./ConfigureAgentDialog.js";
11
+ import "./CheckSessionHealthDialog.js";
9
12
  import "./CreateSessionDialog.js";
10
13
  import "./PluginUIPanel.js";
11
14
  import "./OpenInBrowserEditorButton.js";
@@ -0,0 +1,59 @@
1
+ import { useSetupAgentGatewayAuthMutation as e } from "../generated/wspace-operations.js";
2
+ import { useCallback as t, useSyncExternalStore as n } from "react";
3
+ //#region src/hooks/useRepairGatewayAuth.ts
4
+ var r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set();
5
+ function o() {
6
+ for (let e of a) e();
7
+ }
8
+ function s(e) {
9
+ let t = (i.get(e) ?? 0) + 1;
10
+ return i.set(e, t), o(), t;
11
+ }
12
+ function c(e) {
13
+ return a.add(e), () => {
14
+ a.delete(e);
15
+ };
16
+ }
17
+ function l(a) {
18
+ let [l] = e(), u = n(c, () => a ? r.has(a) : !1, () => !1), d = n(c, () => a ? i.get(a) ?? 0 : 0, () => 0);
19
+ return {
20
+ repair: t(async () => {
21
+ if (!a) return {
22
+ status: "failed",
23
+ message: "No agent"
24
+ };
25
+ if (r.has(a)) return { status: "busy" };
26
+ r.add(a), o();
27
+ try {
28
+ let { data: e, error: t } = await l({ variables: { input: { agentId: a } } }), n = e?.setupAgentGatewayAuth;
29
+ return n ? n.error ? n.clientSecret ? {
30
+ status: "delivery-failed",
31
+ clientSecret: n.clientSecret,
32
+ error: n.error,
33
+ epoch: s(a)
34
+ } : {
35
+ status: "failed",
36
+ message: n.error
37
+ } : n.clientSecret ? {
38
+ status: "ok",
39
+ clientSecret: n.clientSecret,
40
+ epoch: s(a)
41
+ } : { status: "unchanged" } : {
42
+ status: "failed",
43
+ message: t?.message || "No result returned from setupAgentGatewayAuth"
44
+ };
45
+ } catch (e) {
46
+ return {
47
+ status: "failed",
48
+ message: e instanceof Error ? e.message : String(e)
49
+ };
50
+ } finally {
51
+ r.delete(a), o();
52
+ }
53
+ }, [a, l]),
54
+ running: u,
55
+ rotationEpoch: d
56
+ };
57
+ }
58
+ //#endregion
59
+ export { l as useRepairGatewayAuth };