@burdenoff/microfe-vibecontrols 2026.625.3 → 2026.626.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 (59) hide show
  1. package/dist/components/agents/AgentForm.js +129 -127
  2. package/dist/components/agents/AgentForm.js.map +1 -1
  3. package/dist/components/shared/InstallTabs.js +19 -7
  4. package/dist/components/shared/InstallTabs.js.map +1 -1
  5. package/dist/pages/ActionsPage.js +209 -204
  6. package/dist/pages/ActionsPage.js.map +1 -1
  7. package/dist/pages/AgentDetailsPage.js +678 -648
  8. package/dist/pages/AgentDetailsPage.js.map +1 -1
  9. package/dist/pages/AgentGraphPage.js +112 -108
  10. package/dist/pages/AgentGraphPage.js.map +1 -1
  11. package/dist/pages/AgentsPage.js +159 -155
  12. package/dist/pages/AgentsPage.js.map +1 -1
  13. package/dist/pages/AnalyticsPage.js +140 -136
  14. package/dist/pages/AnalyticsPage.js.map +1 -1
  15. package/dist/pages/CatalogDetailPage.js +249 -244
  16. package/dist/pages/CatalogDetailPage.js.map +1 -1
  17. package/dist/pages/CatalogPage.js +73 -68
  18. package/dist/pages/CatalogPage.js.map +1 -1
  19. package/dist/pages/ComponentDetailPage.js +195 -164
  20. package/dist/pages/ComponentDetailPage.js.map +1 -1
  21. package/dist/pages/ComponentsPage.js +80 -75
  22. package/dist/pages/ComponentsPage.js.map +1 -1
  23. package/dist/pages/EnvTopologyPage.js +100 -95
  24. package/dist/pages/EnvTopologyPage.js.map +1 -1
  25. package/dist/pages/HealthPage.js +331 -204
  26. package/dist/pages/HealthPage.js.map +1 -1
  27. package/dist/pages/LogsPage.js +54 -49
  28. package/dist/pages/LogsPage.js.map +1 -1
  29. package/dist/pages/OverviewPage.js +159 -129
  30. package/dist/pages/OverviewPage.js.map +1 -1
  31. package/dist/pages/PluginsCatalogPage.js +72 -78
  32. package/dist/pages/PluginsCatalogPage.js.map +1 -1
  33. package/dist/pages/SessionDetailsPage.js +517 -512
  34. package/dist/pages/SessionDetailsPage.js.map +1 -1
  35. package/dist/pages/SessionsPage.js +1084 -1079
  36. package/dist/pages/SessionsPage.js.map +1 -1
  37. package/dist/pages/SettingsPage.js +107 -103
  38. package/dist/pages/SettingsPage.js.map +1 -1
  39. package/dist/pages/TargetDetailsPage.js +131 -123
  40. package/dist/pages/TargetDetailsPage.js.map +1 -1
  41. package/dist/pages/TargetsPage.js +198 -194
  42. package/dist/pages/TargetsPage.js.map +1 -1
  43. package/dist/pages/TemplatesPage.js +77 -71
  44. package/dist/pages/TemplatesPage.js.map +1 -1
  45. package/dist/pages/VibeAuditPage.js +83 -78
  46. package/dist/pages/VibeAuditPage.js.map +1 -1
  47. package/dist/pages/VibeCalendarPage.js +109 -104
  48. package/dist/pages/VibeCalendarPage.js.map +1 -1
  49. package/dist/pages/VibeDeckPage.js +222 -217
  50. package/dist/pages/VibeDeckPage.js.map +1 -1
  51. package/dist/pages/VibeDetailsPage.js +532 -501
  52. package/dist/pages/VibeDetailsPage.js.map +1 -1
  53. package/dist/pages/VibesPage.js +137 -133
  54. package/dist/pages/VibesPage.js.map +1 -1
  55. package/dist/pages/WebhooksPage.js +329 -324
  56. package/dist/pages/WebhooksPage.js.map +1 -1
  57. package/dist/pages/ai/AIPage.js +149 -144
  58. package/dist/pages/ai/AIPage.js.map +1 -1
  59. package/package.json +2 -2
@@ -15,25 +15,25 @@ import { notify as u } from "../lib/toast.js";
15
15
  import { MeshGraphView as se } from "../components/graph/MeshGraphView.js";
16
16
  import { MeshDeployWizard as ce } from "../components/graph/MeshDeployWizard.js";
17
17
  import { MeshRequestPanel as le } from "../components/graph/MeshRequestPanel.js";
18
- import { MeshNodeActions as ue } from "../components/graph/MeshNodeActions.js";
19
- import { useCallback as d, useMemo as f, useState as p } from "react";
20
- import { GitBranch as de, Loader2 as m, Network as h, Rocket as fe, Send as pe, ShieldAlert as me } from "lucide-react";
21
- import { usePermissions as he } from "@burdenoff/fe-libs/shared/providers/shell";
22
- import { Fragment as ge, jsx as g, jsxs as _ } from "react/jsx-runtime";
23
- import { Button as v } from "@burdenoff/fe-libs/ui";
18
+ import { MeshNodeActions as d } from "../components/graph/MeshNodeActions.js";
19
+ import { useCallback as f, useMemo as p, useState as m } from "react";
20
+ import { GitBranch as ue, Loader2 as h, Network as g, Rocket as de, Send as fe, ShieldAlert as pe } from "lucide-react";
21
+ import { usePermissions as me } from "@burdenoff/fe-libs/shared/providers/shell";
22
+ import { Fragment as he, jsx as _, jsxs as v } from "react/jsx-runtime";
23
+ import { Button as y, PagePurpose as ge } from "@burdenoff/fe-libs/ui";
24
24
  import { MotionPage as _e } from "@burdenoff/fe-libs/shared/motion";
25
25
  //#region src/pages/AgentGraphPage.tsx
26
- function y() {
27
- let { workspaceId: y, currentUser: ve } = te(), b = ne(), x = ee(), { hasPermission: ye, isLoading: be, permissions: S } = he(), [C, xe] = p(null), { agents: w } = a(), T = f(() => w.map((e) => ({
26
+ function b() {
27
+ let { workspaceId: b, currentUser: ve } = te(), x = ne(), S = ee(), { hasPermission: ye, isLoading: be, permissions: C } = me(), [w, xe] = m(null), { agents: T } = a(), E = p(() => T.map((e) => ({
28
28
  value: e.id,
29
- label: x("agentGraph.scopeAgentPrefix", "Agent: {{name}}", { name: e.name })
30
- })), [w, x]), [E, D] = p(""), { data: O } = e({ skip: !y }), k = O?.agentConnectionConfig.permissions ?? [], A = O?.agentConnectionConfig.scopes ?? [], { data: j, previousData: M, loading: Se, error: N, refetch: P } = t({
29
+ label: S("agentGraph.scopeAgentPrefix", "Agent: {{name}}", { name: e.name })
30
+ })), [T, S]), [D, O] = m(""), { data: k } = e({ skip: !b }), A = k?.agentConnectionConfig.permissions ?? [], j = k?.agentConnectionConfig.scopes ?? [], { data: M, previousData: Se, loading: Ce, error: N, refetch: P } = t({
31
31
  variables: {
32
- workspaceId: y || "",
33
- rootAgentId: C || void 0
32
+ workspaceId: b || "",
33
+ rootAgentId: w || void 0
34
34
  },
35
- skip: !y
36
- }), F = j?.agentMeshGraph ?? M?.agentMeshGraph, I = f(() => (F?.agents ?? []).map((e) => ({
35
+ skip: !b
36
+ }), F = M?.agentMeshGraph ?? Se?.agentMeshGraph, I = p(() => (F?.agents ?? []).map((e) => ({
37
37
  id: e.id,
38
38
  name: e.name,
39
39
  hostname: e.hostname,
@@ -49,7 +49,7 @@ function y() {
49
49
  type: String(e.target.type),
50
50
  host: e.target.host ?? null
51
51
  } : null
52
- })), [F]), L = f(() => (F?.meshLinks ?? []).map((e) => ({
52
+ })), [F]), L = p(() => (F?.meshLinks ?? []).map((e) => ({
53
53
  id: e.id,
54
54
  workspaceId: e.workspaceId,
55
55
  status: e.status,
@@ -74,17 +74,17 @@ function y() {
74
74
  host: e.destinationAgent.target.host ?? null
75
75
  } : null
76
76
  }
77
- })), [F]), R = Se, Ce = R && !F, z = R && !!F, B = f(() => I.length > 0 ? I.map((e) => ({
77
+ })), [F]), R = Ce, we = R && !F, z = R && !!F, B = p(() => I.length > 0 ? I.map((e) => ({
78
78
  id: e.id,
79
79
  name: e.name,
80
80
  hostname: e.hostname,
81
81
  isActive: e.isActive
82
- })) : w.map((e) => ({
82
+ })) : T.map((e) => ({
83
83
  id: e.id,
84
84
  name: e.name,
85
85
  hostname: e.hostname,
86
86
  isActive: e.isActive
87
- })), [I, w]), [V] = r(), [H] = n(), [U] = i(), [we, W] = p(!1), [Te, G] = p(null), [Ee, K] = p(!1), [De, q] = p(null), [J, Y] = p(null), Oe = d(async (e, t, n) => {
87
+ })), [I, T]), [V] = r(), [H] = n(), [U] = i(), [Te, W] = m(!1), [Ee, G] = m(null), [De, K] = m(!1), [Oe, q] = m(null), [J, Y] = m(null), ke = f(async (e, t, n) => {
88
88
  await V({ variables: {
89
89
  meshLinkId: e,
90
90
  input: {
@@ -92,13 +92,13 @@ function y() {
92
92
  scopes: n
93
93
  }
94
94
  } }), await P();
95
- }, [P, V]), X = C ?? B[0]?.id ?? null, ke = d(async (e) => {
95
+ }, [P, V]), X = w ?? B[0]?.id ?? null, Ae = f(async (e) => {
96
96
  if (Y(null), X && e === X) {
97
- b(`/agents/${e}?tab=terminal`);
97
+ x(`/agents/${e}?tab=terminal`);
98
98
  return;
99
99
  }
100
100
  if (!X) {
101
- u.error(x("mesh.terminal.noRoot", "No reachable root agent to start a terminal from."));
101
+ u.error(S("mesh.terminal.noRoot", "No reachable root agent to start a terminal from."));
102
102
  return;
103
103
  }
104
104
  try {
@@ -106,27 +106,27 @@ function y() {
106
106
  rootAgentId: X,
107
107
  destinationAgentId: e,
108
108
  input: { kind: re.Terminal }
109
- } }), b(`/agents/${e}?tab=terminal`);
109
+ } }), x(`/agents/${e}?tab=terminal`);
110
110
  } catch {
111
- u.info(x("mesh.terminal.comingSoon", "Deep-terminal coming soon"));
111
+ u.info(S("mesh.terminal.comingSoon", "Deep-terminal coming soon"));
112
112
  }
113
113
  }, [
114
114
  X,
115
115
  H,
116
- b,
117
- x
118
- ]), Ae = d((e) => {
116
+ x,
117
+ S
118
+ ]), je = f((e) => {
119
119
  Y(null), q(e), K(!0);
120
- }, []), je = d((e) => {
120
+ }, []), Me = f((e) => {
121
121
  Y(null), G(e), W(!0);
122
- }, []), Me = d(async (e) => {
122
+ }, []), Z = f(async (e) => {
123
123
  let t = I.find((t) => t.id === e)?.name ?? e;
124
- u.info(x("mesh.wake.starting", "Reconnecting {{name}} over SSH…", { name: t }));
124
+ u.info(S("mesh.wake.starting", "Reconnecting {{name}} over SSH…", { name: t }));
125
125
  try {
126
126
  let { data: n } = await U({ variables: { agentId: e } }), r = n?.wakeMeshAgent;
127
- r?.ok ? (u.success(x("mesh.wake.success", "{{name}} is back online", { name: t })), await P()) : u.error(r?.error ?? x("mesh.wake.failed", "Could not wake {{name}} over SSH.", { name: t }));
127
+ r?.ok ? (u.success(S("mesh.wake.success", "{{name}} is back online", { name: t })), await P()) : u.error(r?.error ?? S("mesh.wake.failed", "Could not wake {{name}} over SSH.", { name: t }));
128
128
  } catch (e) {
129
- u.error(e instanceof Error ? e.message : x("mesh.wake.failed", "Could not wake {{name}} over SSH.", { name: t }));
129
+ u.error(e instanceof Error ? e.message : S("mesh.wake.failed", "Could not wake {{name}} over SSH.", { name: t }));
130
130
  } finally {
131
131
  Y(null);
132
132
  }
@@ -134,168 +134,172 @@ function y() {
134
134
  I,
135
135
  U,
136
136
  P,
137
- x
138
- ]), Z = d((e) => {
139
- Y(null), b(`/agents/${e}`);
140
- }, [b]), Ne = d((e) => {
137
+ S
138
+ ]), Ne = f((e) => {
139
+ Y(null), x(`/agents/${e}`);
140
+ }, [x]), Pe = f((e) => {
141
141
  Y(e);
142
- }, []), Q = f(() => I.find((e) => e.id === J) ?? null, [I, J]);
143
- if (be) return /* @__PURE__ */ g(s, { message: x("agentGraph.loadingPermissions", "Loading permissions...") });
144
- if (S && (S.permissionStrings?.length ?? 0) > 0 && !ye(oe.AGENT_READ)) return /* @__PURE__ */ g(l, {
145
- icon: /* @__PURE__ */ g(me, { className: "size-8 text-text-secondary" }),
146
- title: x("agentGraph.accessDeniedTitle", "Access Denied"),
147
- description: x("agentGraph.accessDeniedDescription", "You don't have permission to access this page.")
142
+ }, []), Q = p(() => I.find((e) => e.id === J) ?? null, [I, J]);
143
+ if (be) return /* @__PURE__ */ _(s, { message: S("agentGraph.loadingPermissions", "Loading permissions...") });
144
+ if (C && (C.permissionStrings?.length ?? 0) > 0 && !ye(oe.AGENT_READ)) return /* @__PURE__ */ _(l, {
145
+ icon: /* @__PURE__ */ _(pe, { className: "size-8 text-text-secondary" }),
146
+ title: S("agentGraph.accessDeniedTitle", "Access Denied"),
147
+ description: S("agentGraph.accessDeniedDescription", "You don't have permission to access this page.")
148
148
  });
149
149
  let $ = I.length > 0;
150
- return /* @__PURE__ */ _(_e, {
150
+ return /* @__PURE__ */ v(_e, {
151
151
  className: "flex h-full min-h-0 flex-col px-6 lg:px-8 pt-6",
152
152
  children: [
153
- /* @__PURE__ */ g(o, {
154
- title: x("nav.agentGraph", "Agent Mesh"),
155
- description: x("agentGraph.meshDescription", "Visualize and manage the agent-to-agent mesh: deploy new agents, edit link permissions, and run requests across hops."),
156
- actions: /* @__PURE__ */ _("div", {
153
+ /* @__PURE__ */ _(o, {
154
+ title: S("nav.agentGraph", "Agent Mesh"),
155
+ description: S("agentGraph.meshDescription", "Visualize and manage the agent-to-agent mesh: deploy new agents, edit link permissions, and run requests across hops."),
156
+ actions: /* @__PURE__ */ v("div", {
157
157
  className: "flex flex-wrap items-center gap-2",
158
- children: [/* @__PURE__ */ _(v, {
158
+ children: [/* @__PURE__ */ v(y, {
159
159
  type: "button",
160
160
  variant: "outline",
161
161
  onClick: () => {
162
162
  K((e) => !e), q(null);
163
163
  },
164
- children: [/* @__PURE__ */ g(pe, {
164
+ children: [/* @__PURE__ */ _(fe, {
165
165
  className: "size-4",
166
166
  "aria-hidden": "true"
167
- }), x("mesh.requestPanelToggle", "Mesh request")]
168
- }), /* @__PURE__ */ _(v, {
167
+ }), S("mesh.requestPanelToggle", "Mesh request")]
168
+ }), /* @__PURE__ */ v(y, {
169
169
  type: "button",
170
170
  onClick: () => {
171
- G(C), W(!0);
171
+ G(w), W(!0);
172
172
  },
173
173
  disabled: B.length === 0,
174
- children: [/* @__PURE__ */ g(fe, {
174
+ children: [/* @__PURE__ */ _(de, {
175
175
  className: "size-4",
176
176
  "aria-hidden": "true"
177
- }), x("mesh.deployButton", "Deploy Agent")]
177
+ }), S("mesh.deployButton", "Deploy Agent")]
178
178
  })]
179
179
  })
180
180
  }),
181
- Ce && /* @__PURE__ */ g(s, { message: x("agentGraph.loading", "Loading agent mesh...") }),
182
- !R && N && !$ && /* @__PURE__ */ g(c, {
183
- title: x("agentGraph.failedLoad", "Failed to load agent mesh"),
181
+ /* @__PURE__ */ _(ge, {
182
+ icon: /* @__PURE__ */ _(g, { className: "size-4" }),
183
+ children: S("agentGraph.purpose", "The Agent Mesh shows how your agents connect to one another and lets you manage those links. Use it to picture the topology, grant or revoke which agents may reach which, deploy a new agent into the mesh, and run a request that hops across agents — handy when work on one machine needs to trigger another.")
184
+ }),
185
+ we && /* @__PURE__ */ _(s, { message: S("agentGraph.loading", "Loading agent mesh...") }),
186
+ !R && N && !$ && /* @__PURE__ */ _(c, {
187
+ title: S("agentGraph.failedLoad", "Failed to load agent mesh"),
184
188
  message: N.message
185
189
  }),
186
- !R && !N && !$ && !E && /* @__PURE__ */ g(l, {
187
- icon: /* @__PURE__ */ g(h, { className: "size-8 text-text-secondary" }),
188
- title: x("agentGraph.noAgentsConnected", "No agents in the mesh"),
189
- description: x("agentGraph.noAgentsDescription", "Deploy an agent to start building your agent mesh topology."),
190
- action: /* @__PURE__ */ g(ie, { prompt: "What is the Agent Mesh in VibeControls and how do I deploy agents?" })
190
+ !R && !N && !$ && !D && /* @__PURE__ */ _(l, {
191
+ icon: /* @__PURE__ */ _(g, { className: "size-8 text-text-secondary" }),
192
+ title: S("agentGraph.noAgentsConnected", "No agents in the mesh"),
193
+ description: S("agentGraph.noAgentsDescription", "Deploy an agent to start building your agent mesh topology."),
194
+ action: /* @__PURE__ */ _(ie, { prompt: "What is the Agent Mesh in VibeControls and how do I deploy agents?" })
191
195
  }),
192
- Ee && /* @__PURE__ */ g("div", {
196
+ De && /* @__PURE__ */ _("div", {
193
197
  className: "mt-4",
194
- children: /* @__PURE__ */ g(le, {
198
+ children: /* @__PURE__ */ _(le, {
195
199
  rootAgentId: X,
196
200
  destinations: I,
197
- initialDestinationId: De,
201
+ initialDestinationId: Oe,
198
202
  onClose: () => K(!1)
199
203
  })
200
204
  }),
201
- ($ || E || z) && /* @__PURE__ */ _(ge, { children: [
202
- /* @__PURE__ */ _("div", {
205
+ ($ || D || z) && /* @__PURE__ */ v(he, { children: [
206
+ /* @__PURE__ */ v("div", {
203
207
  className: "mt-4 flex flex-wrap items-center justify-between gap-3",
204
- children: [/* @__PURE__ */ _("div", {
208
+ children: [/* @__PURE__ */ v("div", {
205
209
  className: "flex min-w-0 flex-wrap items-center gap-2",
206
210
  children: [
207
- /* @__PURE__ */ g(de, {
211
+ /* @__PURE__ */ _(ue, {
208
212
  className: "size-4 shrink-0 text-text-muted",
209
213
  "aria-hidden": "true"
210
214
  }),
211
- /* @__PURE__ */ g("span", {
215
+ /* @__PURE__ */ _("span", {
212
216
  className: "text-sm font-medium text-text-secondary",
213
- children: x("agentGraph.meshCountSummary", "{{agents}} agents, {{links}} links", {
217
+ children: S("agentGraph.meshCountSummary", "{{agents}} agents, {{links}} links", {
214
218
  agents: I.length,
215
219
  links: L.length
216
220
  })
217
221
  }),
218
- z && /* @__PURE__ */ _("span", {
222
+ z && /* @__PURE__ */ v("span", {
219
223
  role: "status",
220
224
  "aria-live": "polite",
221
225
  className: "inline-flex items-center gap-1.5 rounded-full border border-border-default bg-bg-surface px-2.5 py-1 text-xs font-medium text-text-secondary",
222
- children: [/* @__PURE__ */ g(m, {
226
+ children: [/* @__PURE__ */ _(h, {
223
227
  className: "size-3.5 animate-spin text-text-secondary",
224
228
  "aria-hidden": "true"
225
- }), x("agentGraph.refreshing", "Refreshing graph...")]
229
+ }), S("agentGraph.refreshing", "Refreshing graph...")]
226
230
  })
227
231
  ]
228
- }), /* @__PURE__ */ _("div", {
232
+ }), /* @__PURE__ */ v("div", {
229
233
  className: "flex min-w-0 items-center gap-2",
230
- children: [/* @__PURE__ */ g("span", {
234
+ children: [/* @__PURE__ */ _("span", {
231
235
  className: "shrink-0 text-xs font-medium text-text-secondary",
232
- children: x("agentGraph.scopeLabel", "Scope:")
233
- }), /* @__PURE__ */ g(ae, {
234
- value: E,
236
+ children: S("agentGraph.scopeLabel", "Scope:")
237
+ }), /* @__PURE__ */ _(ae, {
238
+ value: D,
235
239
  onChange: (e) => {
236
- D(e), xe(e || null);
240
+ O(e), xe(e || null);
237
241
  },
238
- options: T,
239
- placeholder: x("agentGraph.scopeAllAgents", "All agents"),
242
+ options: E,
243
+ placeholder: S("agentGraph.scopeAllAgents", "All agents"),
240
244
  clearable: !0,
241
245
  disabled: R,
242
246
  dropdownAlign: "right"
243
247
  })]
244
248
  })]
245
249
  }),
246
- !R && N && /* @__PURE__ */ g(c, {
247
- title: x("agentGraph.failedRefresh", "Failed to refresh agent mesh"),
250
+ !R && N && /* @__PURE__ */ _(c, {
251
+ title: S("agentGraph.failedRefresh", "Failed to refresh agent mesh"),
248
252
  message: N.message
249
253
  }),
250
- !R && !$ && E && /* @__PURE__ */ g(l, {
251
- icon: /* @__PURE__ */ g(h, { className: "size-8 text-text-secondary" }),
252
- title: x("agentGraph.noScopeResults", "No results for this scope"),
253
- description: x("agentGraph.noScopeAgentDescription", "No agents match the selected scope. Clear the filter to view the full mesh.")
254
+ !R && !$ && D && /* @__PURE__ */ _(l, {
255
+ icon: /* @__PURE__ */ _(g, { className: "size-8 text-text-secondary" }),
256
+ title: S("agentGraph.noScopeResults", "No results for this scope"),
257
+ description: S("agentGraph.noScopeAgentDescription", "No agents match the selected scope. Clear the filter to view the full mesh.")
254
258
  }),
255
- ($ || z) && /* @__PURE__ */ _("div", {
259
+ ($ || z) && /* @__PURE__ */ v("div", {
256
260
  className: "relative mt-4 min-h-[24rem] flex-1",
257
261
  "aria-busy": z,
258
262
  children: [
259
- /* @__PURE__ */ g(se, {
263
+ /* @__PURE__ */ _(se, {
260
264
  agents: I,
261
265
  meshLinks: L,
262
266
  currentUserId: ve?.id ?? null,
263
- onUpdatePermissions: Oe,
264
- availablePermissions: k,
265
- availableScopes: A,
266
- onNodeClick: Ne,
267
+ onUpdatePermissions: ke,
268
+ availablePermissions: A,
269
+ availableScopes: j,
270
+ onNodeClick: Pe,
267
271
  fullHeight: !0
268
272
  }),
269
- Q && /* @__PURE__ */ g("div", {
273
+ Q && /* @__PURE__ */ _("div", {
270
274
  className: "absolute right-4 top-4 z-20",
271
- children: /* @__PURE__ */ g(ue, {
275
+ children: /* @__PURE__ */ _(d, {
272
276
  agent: Q,
273
- onRunCommand: Ae,
274
- onStartTerminal: (e) => void ke(e),
275
- onDeployFromHere: je,
276
- onWakeViaSsh: Me,
277
- onOpenAgent: Z,
277
+ onRunCommand: je,
278
+ onStartTerminal: (e) => void Ae(e),
279
+ onDeployFromHere: Me,
280
+ onWakeViaSsh: Z,
281
+ onOpenAgent: Ne,
278
282
  onClose: () => Y(null)
279
283
  })
280
284
  }),
281
- z && /* @__PURE__ */ g("div", {
285
+ z && /* @__PURE__ */ _("div", {
282
286
  className: "absolute inset-0 z-10 flex items-center justify-center bg-bg-surface/60 backdrop-blur-[1px]",
283
- children: /* @__PURE__ */ _("div", {
287
+ children: /* @__PURE__ */ v("div", {
284
288
  role: "status",
285
289
  className: "inline-flex items-center gap-2 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-secondary shadow-[var(--shadow-elevation-2)]",
286
- children: [/* @__PURE__ */ g(m, {
290
+ children: [/* @__PURE__ */ _(h, {
287
291
  className: "size-4 animate-spin text-text-secondary",
288
292
  "aria-hidden": "true"
289
- }), /* @__PURE__ */ g("span", { children: E ? x("agentGraph.loadingScope", "Applying selected scope...") : x("agentGraph.refreshing", "Refreshing graph...") })]
293
+ }), /* @__PURE__ */ _("span", { children: D ? S("agentGraph.loadingScope", "Applying selected scope...") : S("agentGraph.refreshing", "Refreshing graph...") })]
290
294
  })
291
295
  })
292
296
  ]
293
297
  })
294
298
  ] }),
295
- we && /* @__PURE__ */ g(ce, {
299
+ Te && /* @__PURE__ */ _(ce, {
296
300
  sourceAgents: B,
297
- initialSourceAgentId: Te,
298
- availablePermissions: k,
301
+ initialSourceAgentId: Ee,
302
+ availablePermissions: A,
299
303
  onClose: () => W(!1),
300
304
  onCompleted: () => {
301
305
  P();
@@ -305,6 +309,6 @@ function y() {
305
309
  });
306
310
  }
307
311
  //#endregion
308
- export { y as AgentGraphPage };
312
+ export { b as AgentGraphPage };
309
313
 
310
314
  //# sourceMappingURL=AgentGraphPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AgentGraphPage.js","names":[],"sources":["../../src/pages/AgentGraphPage.tsx"],"sourcesContent":["/**\n * Agent Graph Page — Dedicated full-page view of the agent MESH graph.\n *\n * Agents are first-class nodes; AgentMeshLinks are the directed agent->agent\n * edges. Supports root-agent scoping, RBAC permission editing on links, a\n * \"Deploy Agent\" wizard, and an on-demand mesh request panel + per-node\n * quick-actions.\n */\n\nimport { useState, useMemo, useCallback } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport { GitBranch, Loader2, Network, Rocket, Send, ShieldAlert } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport {\n PageHeader,\n SearchableSelect,\n LoadingState,\n ErrorState,\n EmptyState,\n GetHelpButton,\n} from '@/components/shared';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { useTr } from '@/shared/hooks/useTr';\nimport { notify } from '@/lib/toast';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport {\n useGetAgentMeshGraphQuery,\n useUpdateMeshLinkPermissionsMutation,\n useStartMeshAgentSessionMutation,\n useWakeMeshAgentMutation,\n useAgentConnectionConfigQuery,\n} from '@/generated/wspace-operations';\nimport { MeshSessionKind } from '@/generated/wspace-types';\nimport type { GetAgentMeshGraphQuery } from '@/generated/wspace-operations';\nimport { MeshGraphView } from '@/components/graph/MeshGraphView';\nimport { MeshDeployWizard } from '@/components/graph/MeshDeployWizard';\nimport { MeshRequestPanel } from '@/components/graph/MeshRequestPanel';\nimport { MeshNodeActions } from '@/components/graph/MeshNodeActions';\nimport type { MeshAgentUi, MeshLinkUi } from '@/components/graph/meshTypes';\n\nexport function AgentGraphPage() {\n const { workspaceId, currentUser } = useVibeControls();\n const navigate = useVibeNavigate();\n const tr = useTr();\n const { hasPermission, isLoading: permissionsLoading, permissions } = usePermissions();\n const [rootAgentId, setRootAgentId] = useState<string | null>(null);\n\n const { agents: cachedAgents } = useCachedInitialData();\n\n const scopeOptions = useMemo(\n () =>\n cachedAgents.map((a) => ({\n value: a.id,\n label: tr('agentGraph.scopeAgentPrefix', 'Agent: {{name}}', { name: a.name }),\n })),\n [cachedAgents, tr]\n );\n\n const [scopeValue, setScopeValue] = useState<string>('');\n\n const { data: connectionConfigData } = useAgentConnectionConfigQuery({\n skip: !workspaceId,\n });\n const availablePermissions = connectionConfigData?.agentConnectionConfig.permissions ?? [];\n const availableScopes = connectionConfigData?.agentConnectionConfig.scopes ?? [];\n\n const {\n data: graphData,\n previousData,\n loading,\n error,\n refetch,\n } = useGetAgentMeshGraphQuery({\n variables: {\n workspaceId: workspaceId || '',\n rootAgentId: rootAgentId || undefined,\n },\n skip: !workspaceId,\n });\n\n const resolvedMeshGraph: GetAgentMeshGraphQuery['agentMeshGraph'] | undefined =\n graphData?.agentMeshGraph ?? previousData?.agentMeshGraph;\n\n type MeshGraphAgent = GetAgentMeshGraphQuery['agentMeshGraph']['agents'][number];\n type MeshGraphLink = GetAgentMeshGraphQuery['agentMeshGraph']['meshLinks'][number];\n\n // Map generated shapes (enum target.type) into the plain UI shapes.\n const meshAgents = useMemo<MeshAgentUi[]>(\n () =>\n (resolvedMeshGraph?.agents ?? []).map((a: MeshGraphAgent) => ({\n id: a.id,\n name: a.name,\n hostname: a.hostname,\n platform: a.platform,\n version: a.version,\n isActive: a.isActive,\n ownerUserId: a.ownerUserId ?? null,\n targetId: a.targetId,\n tunnelStatus: a.tunnelStatus ?? null,\n target: a.target\n ? {\n id: a.target.id,\n name: a.target.name,\n type: String(a.target.type),\n host: a.target.host ?? null,\n }\n : null,\n })),\n [resolvedMeshGraph]\n );\n\n const meshLinks = useMemo<MeshLinkUi[]>(\n () =>\n (resolvedMeshGraph?.meshLinks ?? []).map((l: MeshGraphLink) => ({\n id: l.id,\n workspaceId: l.workspaceId,\n status: l.status,\n permissions: l.permissions,\n scopes: l.scopes,\n label: l.label ?? null,\n description: l.description ?? null,\n createdAt: l.createdAt,\n updatedAt: l.updatedAt,\n sourceAgent: { id: l.sourceAgent.id, name: l.sourceAgent.name },\n destinationAgent: {\n id: l.destinationAgent.id,\n name: l.destinationAgent.name,\n hostname: l.destinationAgent.hostname,\n target: l.destinationAgent.target\n ? {\n id: l.destinationAgent.target.id,\n name: l.destinationAgent.target.name,\n type: String(l.destinationAgent.target.type),\n host: l.destinationAgent.target.host ?? null,\n }\n : null,\n },\n })),\n [resolvedMeshGraph]\n );\n\n const isGraphLoading = loading;\n const isInitialLoad = isGraphLoading && !resolvedMeshGraph;\n const isRefreshingGraph = isGraphLoading && Boolean(resolvedMeshGraph);\n\n // Source agents available to act as deploy root / request root: prefer the\n // mesh agents (already scoped), fall back to the cached fleet.\n const sourceAgents = useMemo(\n () =>\n meshAgents.length > 0\n ? meshAgents.map((a) => ({\n id: a.id,\n name: a.name,\n hostname: a.hostname,\n isActive: a.isActive,\n }))\n : cachedAgents.map((a) => ({\n id: a.id,\n name: a.name,\n hostname: a.hostname,\n isActive: a.isActive,\n })),\n [meshAgents, cachedAgents]\n );\n\n const [updateMeshLinkPerms] = useUpdateMeshLinkPermissionsMutation();\n const [startMeshSession] = useStartMeshAgentSessionMutation();\n const [wakeMeshAgent] = useWakeMeshAgentMutation();\n\n // ── UI panels ──────────────────────────────────────────────────────────\n const [showDeployWizard, setShowDeployWizard] = useState(false);\n const [deploySeedSourceId, setDeploySeedSourceId] = useState<string | null>(null);\n const [showRequestPanel, setShowRequestPanel] = useState(false);\n const [requestDestinationId, setRequestDestinationId] = useState<string | null>(null);\n const [actionsForAgentId, setActionsForAgentId] = useState<string | null>(null);\n\n const handleUpdatePermissions = useCallback(\n async (meshLinkId: string, perms: string[], scopes: string[]) => {\n await updateMeshLinkPerms({\n variables: { meshLinkId, input: { permissions: perms, scopes } },\n });\n await refetch();\n },\n [refetch, updateMeshLinkPerms]\n );\n\n // The \"request root\" is the scoped root agent, else the first source agent.\n const requestRootAgentId = rootAgentId ?? sourceAgents[0]?.id ?? null;\n\n const handleStartTerminal = useCallback(\n async (agentId: string) => {\n setActionsForAgentId(null);\n // For a DIRECT / root agent, prefer the existing terminal flow.\n if (requestRootAgentId && agentId === requestRootAgentId) {\n navigate(`/agents/${agentId}?tab=terminal`);\n return;\n }\n if (!requestRootAgentId) {\n notify.error(\n tr('mesh.terminal.noRoot', 'No reachable root agent to start a terminal from.')\n );\n return;\n }\n try {\n await startMeshSession({\n variables: {\n rootAgentId: requestRootAgentId,\n destinationAgentId: agentId,\n input: { kind: MeshSessionKind.Terminal },\n },\n });\n // If the agent route ever lands, navigate; for now this rarely succeeds.\n navigate(`/agents/${agentId}?tab=terminal`);\n } catch {\n notify.info(tr('mesh.terminal.comingSoon', 'Deep-terminal coming soon'));\n }\n },\n [requestRootAgentId, startMeshSession, navigate, tr]\n );\n\n const handleRunCommand = useCallback((agentId: string) => {\n setActionsForAgentId(null);\n setRequestDestinationId(agentId);\n setShowRequestPanel(true);\n }, []);\n\n const handleDeployFromHere = useCallback((agentId: string) => {\n setActionsForAgentId(null);\n setDeploySeedSourceId(agentId);\n setShowDeployWizard(true);\n }, []);\n\n const handleWakeViaSsh = useCallback(\n async (agentId: string) => {\n const agentName = meshAgents.find((a) => a.id === agentId)?.name ?? agentId;\n notify.info(tr('mesh.wake.starting', 'Reconnecting {{name}} over SSH…', { name: agentName }));\n try {\n const { data } = await wakeMeshAgent({ variables: { agentId } });\n const result = data?.wakeMeshAgent;\n if (result?.ok) {\n notify.success(tr('mesh.wake.success', '{{name}} is back online', { name: agentName }));\n await refetch();\n } else {\n notify.error(\n result?.error ??\n tr('mesh.wake.failed', 'Could not wake {{name}} over SSH.', { name: agentName })\n );\n }\n } catch (err) {\n notify.error(\n err instanceof Error\n ? err.message\n : tr('mesh.wake.failed', 'Could not wake {{name}} over SSH.', { name: agentName })\n );\n } finally {\n setActionsForAgentId(null);\n }\n },\n [meshAgents, wakeMeshAgent, refetch, tr]\n );\n\n const handleOpenAgent = useCallback(\n (agentId: string) => {\n setActionsForAgentId(null);\n navigate(`/agents/${agentId}`);\n },\n [navigate]\n );\n\n const handleNodeClick = useCallback((agentId: string) => {\n setActionsForAgentId(agentId);\n }, []);\n\n const actionsAgent = useMemo(\n () => meshAgents.find((a) => a.id === actionsForAgentId) ?? null,\n [meshAgents, actionsForAgentId]\n );\n\n if (permissionsLoading)\n return <LoadingState message={tr('agentGraph.loadingPermissions', 'Loading permissions...')} />;\n if (\n permissions &&\n (permissions.permissionStrings?.length ?? 0) > 0 &&\n !hasPermission(VIBE_PERMISSIONS.AGENT_READ)\n )\n return (\n <EmptyState\n icon={<ShieldAlert className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.accessDeniedTitle', 'Access Denied')}\n description={tr(\n 'agentGraph.accessDeniedDescription',\n \"You don't have permission to access this page.\"\n )}\n />\n );\n\n const hasAgents = meshAgents.length > 0;\n\n return (\n <MotionPage className=\"flex h-full min-h-0 flex-col px-6 lg:px-8 pt-6\">\n <PageHeader\n title={tr('nav.agentGraph', 'Agent Mesh')}\n description={tr(\n 'agentGraph.meshDescription',\n 'Visualize and manage the agent-to-agent mesh: deploy new agents, edit link permissions, and run requests across hops.'\n )}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setShowRequestPanel((v) => !v);\n setRequestDestinationId(null);\n }}\n >\n <Send className=\"size-4\" aria-hidden=\"true\" />\n {tr('mesh.requestPanelToggle', 'Mesh request')}\n </Button>\n <Button\n type=\"button\"\n onClick={() => {\n setDeploySeedSourceId(rootAgentId);\n setShowDeployWizard(true);\n }}\n disabled={sourceAgents.length === 0}\n >\n <Rocket className=\"size-4\" aria-hidden=\"true\" />\n {tr('mesh.deployButton', 'Deploy Agent')}\n </Button>\n </div>\n }\n />\n\n {isInitialLoad && (\n <LoadingState message={tr('agentGraph.loading', 'Loading agent mesh...')} />\n )}\n\n {!isGraphLoading && error && !hasAgents && (\n <ErrorState\n title={tr('agentGraph.failedLoad', 'Failed to load agent mesh')}\n message={error.message}\n />\n )}\n\n {!isGraphLoading && !error && !hasAgents && !scopeValue && (\n <EmptyState\n icon={<Network className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.noAgentsConnected', 'No agents in the mesh')}\n description={tr(\n 'agentGraph.noAgentsDescription',\n 'Deploy an agent to start building your agent mesh topology.'\n )}\n action={\n <GetHelpButton prompt=\"What is the Agent Mesh in VibeControls and how do I deploy agents?\" />\n }\n />\n )}\n\n {showRequestPanel && (\n <div className=\"mt-4\">\n <MeshRequestPanel\n rootAgentId={requestRootAgentId}\n destinations={meshAgents}\n initialDestinationId={requestDestinationId}\n onClose={() => setShowRequestPanel(false)}\n />\n </div>\n )}\n\n {(hasAgents || scopeValue || isRefreshingGraph) && (\n <>\n <div className=\"mt-4 flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-2\">\n <GitBranch className=\"size-4 shrink-0 text-text-muted\" aria-hidden=\"true\" />\n <span className=\"text-sm font-medium text-text-secondary\">\n {tr('agentGraph.meshCountSummary', '{{agents}} agents, {{links}} links', {\n agents: meshAgents.length,\n links: meshLinks.length,\n })}\n </span>\n {isRefreshingGraph && (\n <span\n role=\"status\"\n aria-live=\"polite\"\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default bg-bg-surface px-2.5 py-1 text-xs font-medium text-text-secondary\"\n >\n <Loader2\n className=\"size-3.5 animate-spin text-text-secondary\"\n aria-hidden=\"true\"\n />\n {tr('agentGraph.refreshing', 'Refreshing graph...')}\n </span>\n )}\n </div>\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"shrink-0 text-xs font-medium text-text-secondary\">\n {tr('agentGraph.scopeLabel', 'Scope:')}\n </span>\n <SearchableSelect\n value={scopeValue}\n onChange={(v: string) => {\n setScopeValue(v);\n setRootAgentId(v || null);\n }}\n options={scopeOptions}\n placeholder={tr('agentGraph.scopeAllAgents', 'All agents')}\n clearable\n disabled={isGraphLoading}\n dropdownAlign=\"right\"\n />\n </div>\n </div>\n\n {!isGraphLoading && error && (\n <ErrorState\n title={tr('agentGraph.failedRefresh', 'Failed to refresh agent mesh')}\n message={error.message}\n />\n )}\n\n {!isGraphLoading && !hasAgents && scopeValue && (\n <EmptyState\n icon={<Network className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.noScopeResults', 'No results for this scope')}\n description={tr(\n 'agentGraph.noScopeAgentDescription',\n 'No agents match the selected scope. Clear the filter to view the full mesh.'\n )}\n />\n )}\n\n {(hasAgents || isRefreshingGraph) && (\n <div className=\"relative mt-4 min-h-[24rem] flex-1\" aria-busy={isRefreshingGraph}>\n <MeshGraphView\n agents={meshAgents}\n meshLinks={meshLinks}\n currentUserId={currentUser?.id ?? null}\n onUpdatePermissions={handleUpdatePermissions}\n availablePermissions={availablePermissions}\n availableScopes={availableScopes}\n onNodeClick={handleNodeClick}\n fullHeight\n />\n\n {/* Node quick-actions popover */}\n {actionsAgent && (\n <div className=\"absolute right-4 top-4 z-20\">\n <MeshNodeActions\n agent={actionsAgent}\n onRunCommand={handleRunCommand}\n onStartTerminal={(id) => void handleStartTerminal(id)}\n onDeployFromHere={handleDeployFromHere}\n onWakeViaSsh={handleWakeViaSsh}\n onOpenAgent={handleOpenAgent}\n onClose={() => setActionsForAgentId(null)}\n />\n </div>\n )}\n\n {isRefreshingGraph && (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center bg-bg-surface/60 backdrop-blur-[1px]\">\n <div\n role=\"status\"\n className=\"inline-flex items-center gap-2 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-secondary shadow-[var(--shadow-elevation-2)]\"\n >\n <Loader2\n className=\"size-4 animate-spin text-text-secondary\"\n aria-hidden=\"true\"\n />\n <span>\n {scopeValue\n ? tr('agentGraph.loadingScope', 'Applying selected scope...')\n : tr('agentGraph.refreshing', 'Refreshing graph...')}\n </span>\n </div>\n </div>\n )}\n </div>\n )}\n </>\n )}\n\n {showDeployWizard && (\n <MeshDeployWizard\n sourceAgents={sourceAgents}\n initialSourceAgentId={deploySeedSourceId}\n availablePermissions={availablePermissions}\n onClose={() => setShowDeployWizard(false)}\n onCompleted={() => {\n void refetch();\n }}\n />\n )}\n </MotionPage>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentGraphPage.js","names":[],"sources":["../../src/pages/AgentGraphPage.tsx"],"sourcesContent":["/**\n * Agent Graph Page — Dedicated full-page view of the agent MESH graph.\n *\n * Agents are first-class nodes; AgentMeshLinks are the directed agent->agent\n * edges. Supports root-agent scoping, RBAC permission editing on links, a\n * \"Deploy Agent\" wizard, and an on-demand mesh request panel + per-node\n * quick-actions.\n */\n\nimport { useState, useMemo, useCallback } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport { GitBranch, Loader2, Network, Rocket, Send, ShieldAlert } from 'lucide-react';\nimport { Button, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport {\n PageHeader,\n SearchableSelect,\n LoadingState,\n ErrorState,\n EmptyState,\n GetHelpButton,\n} from '@/components/shared';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { useTr } from '@/shared/hooks/useTr';\nimport { notify } from '@/lib/toast';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport {\n useGetAgentMeshGraphQuery,\n useUpdateMeshLinkPermissionsMutation,\n useStartMeshAgentSessionMutation,\n useWakeMeshAgentMutation,\n useAgentConnectionConfigQuery,\n} from '@/generated/wspace-operations';\nimport { MeshSessionKind } from '@/generated/wspace-types';\nimport type { GetAgentMeshGraphQuery } from '@/generated/wspace-operations';\nimport { MeshGraphView } from '@/components/graph/MeshGraphView';\nimport { MeshDeployWizard } from '@/components/graph/MeshDeployWizard';\nimport { MeshRequestPanel } from '@/components/graph/MeshRequestPanel';\nimport { MeshNodeActions } from '@/components/graph/MeshNodeActions';\nimport type { MeshAgentUi, MeshLinkUi } from '@/components/graph/meshTypes';\n\nexport function AgentGraphPage() {\n const { workspaceId, currentUser } = useVibeControls();\n const navigate = useVibeNavigate();\n const tr = useTr();\n const { hasPermission, isLoading: permissionsLoading, permissions } = usePermissions();\n const [rootAgentId, setRootAgentId] = useState<string | null>(null);\n\n const { agents: cachedAgents } = useCachedInitialData();\n\n const scopeOptions = useMemo(\n () =>\n cachedAgents.map((a) => ({\n value: a.id,\n label: tr('agentGraph.scopeAgentPrefix', 'Agent: {{name}}', { name: a.name }),\n })),\n [cachedAgents, tr]\n );\n\n const [scopeValue, setScopeValue] = useState<string>('');\n\n const { data: connectionConfigData } = useAgentConnectionConfigQuery({\n skip: !workspaceId,\n });\n const availablePermissions = connectionConfigData?.agentConnectionConfig.permissions ?? [];\n const availableScopes = connectionConfigData?.agentConnectionConfig.scopes ?? [];\n\n const {\n data: graphData,\n previousData,\n loading,\n error,\n refetch,\n } = useGetAgentMeshGraphQuery({\n variables: {\n workspaceId: workspaceId || '',\n rootAgentId: rootAgentId || undefined,\n },\n skip: !workspaceId,\n });\n\n const resolvedMeshGraph: GetAgentMeshGraphQuery['agentMeshGraph'] | undefined =\n graphData?.agentMeshGraph ?? previousData?.agentMeshGraph;\n\n type MeshGraphAgent = GetAgentMeshGraphQuery['agentMeshGraph']['agents'][number];\n type MeshGraphLink = GetAgentMeshGraphQuery['agentMeshGraph']['meshLinks'][number];\n\n // Map generated shapes (enum target.type) into the plain UI shapes.\n const meshAgents = useMemo<MeshAgentUi[]>(\n () =>\n (resolvedMeshGraph?.agents ?? []).map((a: MeshGraphAgent) => ({\n id: a.id,\n name: a.name,\n hostname: a.hostname,\n platform: a.platform,\n version: a.version,\n isActive: a.isActive,\n ownerUserId: a.ownerUserId ?? null,\n targetId: a.targetId,\n tunnelStatus: a.tunnelStatus ?? null,\n target: a.target\n ? {\n id: a.target.id,\n name: a.target.name,\n type: String(a.target.type),\n host: a.target.host ?? null,\n }\n : null,\n })),\n [resolvedMeshGraph]\n );\n\n const meshLinks = useMemo<MeshLinkUi[]>(\n () =>\n (resolvedMeshGraph?.meshLinks ?? []).map((l: MeshGraphLink) => ({\n id: l.id,\n workspaceId: l.workspaceId,\n status: l.status,\n permissions: l.permissions,\n scopes: l.scopes,\n label: l.label ?? null,\n description: l.description ?? null,\n createdAt: l.createdAt,\n updatedAt: l.updatedAt,\n sourceAgent: { id: l.sourceAgent.id, name: l.sourceAgent.name },\n destinationAgent: {\n id: l.destinationAgent.id,\n name: l.destinationAgent.name,\n hostname: l.destinationAgent.hostname,\n target: l.destinationAgent.target\n ? {\n id: l.destinationAgent.target.id,\n name: l.destinationAgent.target.name,\n type: String(l.destinationAgent.target.type),\n host: l.destinationAgent.target.host ?? null,\n }\n : null,\n },\n })),\n [resolvedMeshGraph]\n );\n\n const isGraphLoading = loading;\n const isInitialLoad = isGraphLoading && !resolvedMeshGraph;\n const isRefreshingGraph = isGraphLoading && Boolean(resolvedMeshGraph);\n\n // Source agents available to act as deploy root / request root: prefer the\n // mesh agents (already scoped), fall back to the cached fleet.\n const sourceAgents = useMemo(\n () =>\n meshAgents.length > 0\n ? meshAgents.map((a) => ({\n id: a.id,\n name: a.name,\n hostname: a.hostname,\n isActive: a.isActive,\n }))\n : cachedAgents.map((a) => ({\n id: a.id,\n name: a.name,\n hostname: a.hostname,\n isActive: a.isActive,\n })),\n [meshAgents, cachedAgents]\n );\n\n const [updateMeshLinkPerms] = useUpdateMeshLinkPermissionsMutation();\n const [startMeshSession] = useStartMeshAgentSessionMutation();\n const [wakeMeshAgent] = useWakeMeshAgentMutation();\n\n // ── UI panels ──────────────────────────────────────────────────────────\n const [showDeployWizard, setShowDeployWizard] = useState(false);\n const [deploySeedSourceId, setDeploySeedSourceId] = useState<string | null>(null);\n const [showRequestPanel, setShowRequestPanel] = useState(false);\n const [requestDestinationId, setRequestDestinationId] = useState<string | null>(null);\n const [actionsForAgentId, setActionsForAgentId] = useState<string | null>(null);\n\n const handleUpdatePermissions = useCallback(\n async (meshLinkId: string, perms: string[], scopes: string[]) => {\n await updateMeshLinkPerms({\n variables: { meshLinkId, input: { permissions: perms, scopes } },\n });\n await refetch();\n },\n [refetch, updateMeshLinkPerms]\n );\n\n // The \"request root\" is the scoped root agent, else the first source agent.\n const requestRootAgentId = rootAgentId ?? sourceAgents[0]?.id ?? null;\n\n const handleStartTerminal = useCallback(\n async (agentId: string) => {\n setActionsForAgentId(null);\n // For a DIRECT / root agent, prefer the existing terminal flow.\n if (requestRootAgentId && agentId === requestRootAgentId) {\n navigate(`/agents/${agentId}?tab=terminal`);\n return;\n }\n if (!requestRootAgentId) {\n notify.error(\n tr('mesh.terminal.noRoot', 'No reachable root agent to start a terminal from.')\n );\n return;\n }\n try {\n await startMeshSession({\n variables: {\n rootAgentId: requestRootAgentId,\n destinationAgentId: agentId,\n input: { kind: MeshSessionKind.Terminal },\n },\n });\n // If the agent route ever lands, navigate; for now this rarely succeeds.\n navigate(`/agents/${agentId}?tab=terminal`);\n } catch {\n notify.info(tr('mesh.terminal.comingSoon', 'Deep-terminal coming soon'));\n }\n },\n [requestRootAgentId, startMeshSession, navigate, tr]\n );\n\n const handleRunCommand = useCallback((agentId: string) => {\n setActionsForAgentId(null);\n setRequestDestinationId(agentId);\n setShowRequestPanel(true);\n }, []);\n\n const handleDeployFromHere = useCallback((agentId: string) => {\n setActionsForAgentId(null);\n setDeploySeedSourceId(agentId);\n setShowDeployWizard(true);\n }, []);\n\n const handleWakeViaSsh = useCallback(\n async (agentId: string) => {\n const agentName = meshAgents.find((a) => a.id === agentId)?.name ?? agentId;\n notify.info(tr('mesh.wake.starting', 'Reconnecting {{name}} over SSH…', { name: agentName }));\n try {\n const { data } = await wakeMeshAgent({ variables: { agentId } });\n const result = data?.wakeMeshAgent;\n if (result?.ok) {\n notify.success(tr('mesh.wake.success', '{{name}} is back online', { name: agentName }));\n await refetch();\n } else {\n notify.error(\n result?.error ??\n tr('mesh.wake.failed', 'Could not wake {{name}} over SSH.', { name: agentName })\n );\n }\n } catch (err) {\n notify.error(\n err instanceof Error\n ? err.message\n : tr('mesh.wake.failed', 'Could not wake {{name}} over SSH.', { name: agentName })\n );\n } finally {\n setActionsForAgentId(null);\n }\n },\n [meshAgents, wakeMeshAgent, refetch, tr]\n );\n\n const handleOpenAgent = useCallback(\n (agentId: string) => {\n setActionsForAgentId(null);\n navigate(`/agents/${agentId}`);\n },\n [navigate]\n );\n\n const handleNodeClick = useCallback((agentId: string) => {\n setActionsForAgentId(agentId);\n }, []);\n\n const actionsAgent = useMemo(\n () => meshAgents.find((a) => a.id === actionsForAgentId) ?? null,\n [meshAgents, actionsForAgentId]\n );\n\n if (permissionsLoading)\n return <LoadingState message={tr('agentGraph.loadingPermissions', 'Loading permissions...')} />;\n if (\n permissions &&\n (permissions.permissionStrings?.length ?? 0) > 0 &&\n !hasPermission(VIBE_PERMISSIONS.AGENT_READ)\n )\n return (\n <EmptyState\n icon={<ShieldAlert className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.accessDeniedTitle', 'Access Denied')}\n description={tr(\n 'agentGraph.accessDeniedDescription',\n \"You don't have permission to access this page.\"\n )}\n />\n );\n\n const hasAgents = meshAgents.length > 0;\n\n return (\n <MotionPage className=\"flex h-full min-h-0 flex-col px-6 lg:px-8 pt-6\">\n <PageHeader\n title={tr('nav.agentGraph', 'Agent Mesh')}\n description={tr(\n 'agentGraph.meshDescription',\n 'Visualize and manage the agent-to-agent mesh: deploy new agents, edit link permissions, and run requests across hops.'\n )}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setShowRequestPanel((v) => !v);\n setRequestDestinationId(null);\n }}\n >\n <Send className=\"size-4\" aria-hidden=\"true\" />\n {tr('mesh.requestPanelToggle', 'Mesh request')}\n </Button>\n <Button\n type=\"button\"\n onClick={() => {\n setDeploySeedSourceId(rootAgentId);\n setShowDeployWizard(true);\n }}\n disabled={sourceAgents.length === 0}\n >\n <Rocket className=\"size-4\" aria-hidden=\"true\" />\n {tr('mesh.deployButton', 'Deploy Agent')}\n </Button>\n </div>\n }\n />\n\n <PagePurpose icon={<Network className=\"size-4\" />}>\n {tr(\n 'agentGraph.purpose',\n 'The Agent Mesh shows how your agents connect to one another and lets you manage those links. Use it to picture the topology, grant or revoke which agents may reach which, deploy a new agent into the mesh, and run a request that hops across agents — handy when work on one machine needs to trigger another.'\n )}\n </PagePurpose>\n\n {isInitialLoad && (\n <LoadingState message={tr('agentGraph.loading', 'Loading agent mesh...')} />\n )}\n\n {!isGraphLoading && error && !hasAgents && (\n <ErrorState\n title={tr('agentGraph.failedLoad', 'Failed to load agent mesh')}\n message={error.message}\n />\n )}\n\n {!isGraphLoading && !error && !hasAgents && !scopeValue && (\n <EmptyState\n icon={<Network className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.noAgentsConnected', 'No agents in the mesh')}\n description={tr(\n 'agentGraph.noAgentsDescription',\n 'Deploy an agent to start building your agent mesh topology.'\n )}\n action={\n <GetHelpButton prompt=\"What is the Agent Mesh in VibeControls and how do I deploy agents?\" />\n }\n />\n )}\n\n {showRequestPanel && (\n <div className=\"mt-4\">\n <MeshRequestPanel\n rootAgentId={requestRootAgentId}\n destinations={meshAgents}\n initialDestinationId={requestDestinationId}\n onClose={() => setShowRequestPanel(false)}\n />\n </div>\n )}\n\n {(hasAgents || scopeValue || isRefreshingGraph) && (\n <>\n <div className=\"mt-4 flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-2\">\n <GitBranch className=\"size-4 shrink-0 text-text-muted\" aria-hidden=\"true\" />\n <span className=\"text-sm font-medium text-text-secondary\">\n {tr('agentGraph.meshCountSummary', '{{agents}} agents, {{links}} links', {\n agents: meshAgents.length,\n links: meshLinks.length,\n })}\n </span>\n {isRefreshingGraph && (\n <span\n role=\"status\"\n aria-live=\"polite\"\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default bg-bg-surface px-2.5 py-1 text-xs font-medium text-text-secondary\"\n >\n <Loader2\n className=\"size-3.5 animate-spin text-text-secondary\"\n aria-hidden=\"true\"\n />\n {tr('agentGraph.refreshing', 'Refreshing graph...')}\n </span>\n )}\n </div>\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"shrink-0 text-xs font-medium text-text-secondary\">\n {tr('agentGraph.scopeLabel', 'Scope:')}\n </span>\n <SearchableSelect\n value={scopeValue}\n onChange={(v: string) => {\n setScopeValue(v);\n setRootAgentId(v || null);\n }}\n options={scopeOptions}\n placeholder={tr('agentGraph.scopeAllAgents', 'All agents')}\n clearable\n disabled={isGraphLoading}\n dropdownAlign=\"right\"\n />\n </div>\n </div>\n\n {!isGraphLoading && error && (\n <ErrorState\n title={tr('agentGraph.failedRefresh', 'Failed to refresh agent mesh')}\n message={error.message}\n />\n )}\n\n {!isGraphLoading && !hasAgents && scopeValue && (\n <EmptyState\n icon={<Network className=\"size-8 text-text-secondary\" />}\n title={tr('agentGraph.noScopeResults', 'No results for this scope')}\n description={tr(\n 'agentGraph.noScopeAgentDescription',\n 'No agents match the selected scope. Clear the filter to view the full mesh.'\n )}\n />\n )}\n\n {(hasAgents || isRefreshingGraph) && (\n <div className=\"relative mt-4 min-h-[24rem] flex-1\" aria-busy={isRefreshingGraph}>\n <MeshGraphView\n agents={meshAgents}\n meshLinks={meshLinks}\n currentUserId={currentUser?.id ?? null}\n onUpdatePermissions={handleUpdatePermissions}\n availablePermissions={availablePermissions}\n availableScopes={availableScopes}\n onNodeClick={handleNodeClick}\n fullHeight\n />\n\n {/* Node quick-actions popover */}\n {actionsAgent && (\n <div className=\"absolute right-4 top-4 z-20\">\n <MeshNodeActions\n agent={actionsAgent}\n onRunCommand={handleRunCommand}\n onStartTerminal={(id) => void handleStartTerminal(id)}\n onDeployFromHere={handleDeployFromHere}\n onWakeViaSsh={handleWakeViaSsh}\n onOpenAgent={handleOpenAgent}\n onClose={() => setActionsForAgentId(null)}\n />\n </div>\n )}\n\n {isRefreshingGraph && (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center bg-bg-surface/60 backdrop-blur-[1px]\">\n <div\n role=\"status\"\n className=\"inline-flex items-center gap-2 rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-secondary shadow-[var(--shadow-elevation-2)]\"\n >\n <Loader2\n className=\"size-4 animate-spin text-text-secondary\"\n aria-hidden=\"true\"\n />\n <span>\n {scopeValue\n ? tr('agentGraph.loadingScope', 'Applying selected scope...')\n : tr('agentGraph.refreshing', 'Refreshing graph...')}\n </span>\n </div>\n </div>\n )}\n </div>\n )}\n </>\n )}\n\n {showDeployWizard && (\n <MeshDeployWizard\n sourceAgents={sourceAgents}\n initialSourceAgentId={deploySeedSourceId}\n availablePermissions={availablePermissions}\n onClose={() => setShowDeployWizard(false)}\n onCompleted={() => {\n void refetch();\n }}\n />\n )}\n </MotionPage>\n );\n}\n"],"mappings":"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"}