@burdenoff/microfe-vibecontrols 2026.613.1 → 2026.618.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/components/agents/AgentConnectionRecovery.js +100 -94
  2. package/dist/components/agents/AgentConnectionRecovery.js.map +1 -1
  3. package/dist/components/agents/AgentMaintenanceTab.js +177 -160
  4. package/dist/components/agents/AgentMaintenanceTab.js.map +1 -1
  5. package/dist/components/agents/OpenInBrowserEditorButton.js +102 -94
  6. package/dist/components/agents/OpenInBrowserEditorButton.js.map +1 -1
  7. package/dist/components/assistant/AssistantChatArea.js +1 -0
  8. package/dist/components/assistant/AssistantChatArea.js.map +1 -1
  9. package/dist/components/assistant/AssistantModeSelector.js +20 -19
  10. package/dist/components/assistant/AssistantModeSelector.js.map +1 -1
  11. package/dist/components/tunnels/TunnelCard.js +3 -3
  12. package/dist/components/tunnels/TunnelCard.js.map +1 -1
  13. package/dist/components/tunnels/TunnelPublicAccessPanel.js +36 -36
  14. package/dist/components/tunnels/TunnelPublicAccessPanel.js.map +1 -1
  15. package/dist/config/assistantUsecases.js +11 -0
  16. package/dist/config/assistantUsecases.js.map +1 -1
  17. package/dist/constants/permissions.js +38 -6
  18. package/dist/constants/permissions.js.map +1 -1
  19. package/dist/index.js +4 -3
  20. package/dist/pages/CatalogDetailPage.js +155 -155
  21. package/dist/pages/CatalogDetailPage.js.map +1 -1
  22. package/dist/pages/CatalogPage.js +110 -109
  23. package/dist/pages/CatalogPage.js.map +1 -1
  24. package/dist/pages/ComponentDetailPage.js +338 -338
  25. package/dist/pages/ComponentDetailPage.js.map +1 -1
  26. package/dist/pages/ComponentsPage.js +104 -103
  27. package/dist/pages/ComponentsPage.js.map +1 -1
  28. package/dist/pages/TargetDetailsPage.js +140 -132
  29. package/dist/pages/TargetDetailsPage.js.map +1 -1
  30. package/dist/pages/TemplateDetailPage.js +201 -199
  31. package/dist/pages/TemplateDetailPage.js.map +1 -1
  32. package/dist/pages/TemplatesPage.js +62 -61
  33. package/dist/pages/TemplatesPage.js.map +1 -1
  34. package/dist/pages/VibeDetailsPage.js +568 -555
  35. package/dist/pages/VibeDetailsPage.js.map +1 -1
  36. package/dist/pages/ai/AIBookmarksPage.js +104 -89
  37. package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
  38. package/dist/pages/ai/AIPage.js +116 -107
  39. package/dist/pages/ai/AIPage.js.map +1 -1
  40. package/dist/pages/ai/AISessionDetailPage.js +46 -34
  41. package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
  42. package/dist/pages/ai/AgentManagerPage.js +112 -100
  43. package/dist/pages/ai/AgentManagerPage.js.map +1 -1
  44. package/dist/pages/tunnels/TunnelDetailsPage.js +177 -153
  45. package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
  46. package/dist/pages/tunnels/TunnelsTab.js +119 -111
  47. package/dist/pages/tunnels/TunnelsTab.js.map +1 -1
  48. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js +24 -24
  49. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js.map +1 -1
  50. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +9 -8
  51. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
  52. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js +13 -13
  53. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js.map +1 -1
  54. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +19 -15
  55. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js.map +1 -1
  56. package/dist/services/assistantApi.js +9 -3
  57. package/dist/services/assistantApi.js.map +1 -1
  58. package/dist/services/createSandboxAssistantTransport.js +120 -0
  59. package/dist/services/createSandboxAssistantTransport.js.map +1 -0
  60. package/dist/store/assistantStore.js +1 -1
  61. package/dist/store/assistantStore.js.map +1 -1
  62. package/package.json +5 -1
@@ -6,74 +6,77 @@ import ee from "../../hooks/useCachedInitialData.js";
6
6
  import { LoadingState as i } from "../../components/shared/LoadingState.js";
7
7
  import { ErrorState as a } from "../../components/shared/ErrorState.js";
8
8
  import { EmptyState as te } from "../../components/shared/EmptyState.js";
9
- import { usePluginAvailability as ne } from "../../hooks/usePluginAvailability.js";
10
- import { AI_CORE_PACKAGE as o, AI_PROVIDER_PACKAGES as s } from "../../constants/pluginCatalog.js";
11
- import { PluginGate as c } from "../../components/shared/PluginGate.js";
12
- import { RequireAgentReachable as l } from "../../components/shared/RequireAgentReachable.js";
13
- import { useActiveAgentProfile as u } from "../../hooks/useActiveAgentProfile.js";
14
- import { AgentSelector as d } from "../../components/shared/AgentSelector.js";
9
+ import { usePluginAvailability as o } from "../../hooks/usePluginAvailability.js";
10
+ import { AI_CORE_PACKAGE as s, AI_PROVIDER_PACKAGES as c } from "../../constants/pluginCatalog.js";
11
+ import { PluginGate as l } from "../../components/shared/PluginGate.js";
12
+ import { RequireAgentReachable as u } from "../../components/shared/RequireAgentReachable.js";
13
+ import { useActiveAgentProfile as d } from "../../hooks/useActiveAgentProfile.js";
14
+ import { AgentSelector as f } from "../../components/shared/AgentSelector.js";
15
15
  import "../../components/shared/index.js";
16
- import { isNative as f, nativeNotify as p } from "../../utils/nativeBridge.js";
17
- import { bulkDeleteSessions as m, terminateSession as h } from "../../services/aiApi.js";
18
- import { useAgentManagerStore as g } from "../../store/agentManagerStore.js";
19
- import { AgentManagerLayout as _ } from "../../components/agent-manager/AgentManagerLayout.js";
20
- import { AgentManagerSidebar as v } from "../../components/agent-manager/AgentManagerSidebar.js";
21
- import { BridleConfigPanel as re } from "../../components/agent-manager/BridleConfigPanel.js";
22
- import { AgentManagerCenter as ie } from "../../components/agent-manager/AgentManagerCenter.js";
23
- import { AgentManagerDetailPanel as ae } from "../../components/agent-manager/AgentManagerDetailPanel.js";
24
- import { AiSectionTabs as y } from "../../components/ai/AiSectionTabs.js";
25
- import { ClaudeCredentialsCard as b } from "../../components/ai/ClaudeCredentialsCard.js";
26
- import { AIModeToggle as x } from "../../components/ai/AIModeToggle.js";
27
- import { useAgentManagerKeyboard as S } from "../../hooks/useAgentManagerKeyboard.js";
28
- import { Suspense as oe, useCallback as C, useEffect as w, useMemo as T, useRef as E } from "react";
29
- import { MessagesSquare as D } from "lucide-react";
30
- import { useParams as O, useSearchParams as se } from "react-router-dom";
31
- import { useApolloClient as ce } from "@apollo/client/react";
32
- import { jsx as k, jsxs as A } from "react/jsx-runtime";
33
- import { MotionPage as j } from "@burdenoff/fe-libs/shared/motion";
16
+ import { isNative as p, nativeNotify as m } from "../../utils/nativeBridge.js";
17
+ import { VIBE_PERMISSIONS as ne } from "../../constants/permissions.js";
18
+ import { bulkDeleteSessions as re, terminateSession as ie } from "../../services/aiApi.js";
19
+ import { useAgentManagerStore as h } from "../../store/agentManagerStore.js";
20
+ import { AgentManagerLayout as ae } from "../../components/agent-manager/AgentManagerLayout.js";
21
+ import { AgentManagerSidebar as oe } from "../../components/agent-manager/AgentManagerSidebar.js";
22
+ import { BridleConfigPanel as se } from "../../components/agent-manager/BridleConfigPanel.js";
23
+ import { AgentManagerCenter as ce } from "../../components/agent-manager/AgentManagerCenter.js";
24
+ import { AgentManagerDetailPanel as g } from "../../components/agent-manager/AgentManagerDetailPanel.js";
25
+ import { AiSectionTabs as le } from "../../components/ai/AiSectionTabs.js";
26
+ import { ClaudeCredentialsCard as _ } from "../../components/ai/ClaudeCredentialsCard.js";
27
+ import { AIModeToggle as v } from "../../components/ai/AIModeToggle.js";
28
+ import { useAgentManagerKeyboard as y } from "../../hooks/useAgentManagerKeyboard.js";
29
+ import { Suspense as b, useCallback as x, useEffect as S, useMemo as C, useRef as w } from "react";
30
+ import { MessagesSquare as ue } from "lucide-react";
31
+ import { useParams as de, useSearchParams as fe } from "react-router-dom";
32
+ import { useApolloClient as pe } from "@apollo/client/react";
33
+ import { usePermissions as me } from "@burdenoff/fe-libs/shared/providers/shell";
34
+ import { jsx as T, jsxs as E } from "react/jsx-runtime";
35
+ import { AccessDenied as D } from "@burdenoff/fe-libs/shared/components";
36
+ import { MotionPage as O } from "@burdenoff/fe-libs/shared/motion";
34
37
  //#region src/pages/ai/AgentManagerPage.tsx
35
- function M() {
36
- let { tab: M, sessionId: N } = O(), P = t(), F = n(), { agents: I, loading: L, error: R } = ee(), z = r((e) => e.activeAgentId), B = T(() => {
38
+ function k() {
39
+ let { tab: k, sessionId: A } = de(), j = t(), M = n(), { hasPermission: N, isLoading: P } = me(), F = N(ne.AGENT_READ), { agents: I, loading: L, error: R } = ee(), z = r((e) => e.activeAgentId), B = C(() => {
37
40
  if (z) {
38
41
  let e = I.find((e) => e.id === z);
39
42
  if (e) return e;
40
43
  }
41
44
  return I.find((e) => e.isActive && e.tunnelUrl) ?? null;
42
- }, [I, z]), V = B?.id ?? "", { active: H } = u(B?.id ?? null), U = T(() => ({
45
+ }, [I, z]), V = B?.id ?? "", { active: H } = d(B?.id ?? null), U = C(() => ({
43
46
  id: V,
44
47
  profile: H
45
- }), [V, H]), W = g((e) => e.openSession), G = g((e) => e.closeTab), K = g((e) => e.clearSelection), q = g((e) => e.bumpSessionsRefresh), J = g((e) => e.activeTabSessionId), Y = g((e) => e.setActiveChatContext), [X] = se();
46
- w(() => {
48
+ }), [V, H]), W = h((e) => e.openSession), G = h((e) => e.closeTab), K = h((e) => e.clearSelection), q = h((e) => e.bumpSessionsRefresh), J = h((e) => e.activeTabSessionId), Y = h((e) => e.setActiveChatContext), [X] = fe();
49
+ S(() => {
47
50
  let e = X.get("vibeId");
48
51
  Y({
49
52
  contextLevel: e ? "vibe" : "agent",
50
53
  vibeId: e ?? null
51
54
  });
52
55
  }, [X, Y]);
53
- let { initialLoading: le, refetch: Z } = ne(T(() => [o, ...s], []), V || null), Q = ce(), $ = E(!1);
54
- w(() => {
55
- N && V && W(N, `Session ${N.slice(0, 8)}`);
56
+ let { initialLoading: he, refetch: Z } = o(C(() => [s, ...c], []), V || null), Q = pe(), $ = w(!1);
57
+ S(() => {
58
+ A && V && W(A, `Session ${A.slice(0, 8)}`);
56
59
  }, [
57
- N,
60
+ A,
58
61
  V,
59
62
  W
60
63
  ]);
61
- let ue = C(async (e) => {
64
+ let ge = x(async (e) => {
62
65
  if (V) try {
63
- await h(U, e), G(e), q(), f() && p("success");
66
+ await ie(U, e), G(e), q(), p() && m("success");
64
67
  } catch {
65
- f() && p("error");
68
+ p() && m("error");
66
69
  }
67
70
  }, [
68
71
  V,
69
72
  U,
70
73
  q,
71
74
  G
72
- ]), de = C(async (e) => {
75
+ ]), _e = x(async (e) => {
73
76
  if (V) try {
74
- await m(U, e), e.forEach((e) => G(e)), K(), q(), f() && p("success");
77
+ await re(U, e), e.forEach((e) => G(e)), K(), q(), p() && m("success");
75
78
  } catch {
76
- f() && p("error");
79
+ p() && m("error");
77
80
  }
78
81
  }, [
79
82
  V,
@@ -81,7 +84,7 @@ function M() {
81
84
  q,
82
85
  K,
83
86
  G
84
- ]), fe = C(async () => {
87
+ ]), ve = x(async () => {
85
88
  if ($.current || !V) return;
86
89
  $.current = !0;
87
90
  let t = () => {
@@ -90,7 +93,7 @@ function M() {
90
93
  query: e,
91
94
  variables: { agentId: V }
92
95
  }), n = new Set((t?.agentPlugins?.installed ?? []).map((e) => e.packageName));
93
- return s.some((e) => n.has(e));
96
+ return c.some((e) => n.has(e));
94
97
  } catch {
95
98
  return !1;
96
99
  }
@@ -105,7 +108,7 @@ function M() {
105
108
  variables: { agentId: V },
106
109
  fetchPolicy: "network-only"
107
110
  }), n = t?.agentPlugins?.installed ?? [], r = new Set(n.map((e) => e.packageName));
108
- if (s.some((e) => r.has(e))) break;
111
+ if (c.some((e) => r.has(e))) break;
109
112
  } catch (e) {
110
113
  console.warn("[ai] provider poll attempt failed", e);
111
114
  }
@@ -119,123 +122,132 @@ function M() {
119
122
  Q,
120
123
  Z
121
124
  ]);
122
- return S(), L || V && le ? /* @__PURE__ */ k(j, {
125
+ return y(), P ? /* @__PURE__ */ T(O, {
123
126
  className: "flex items-center justify-center h-full bg-bg-surface",
124
- children: /* @__PURE__ */ k(i, { message: P("vibecontrols.pages.ai.detectingAgent", "Detecting agent and plugin availability…") })
125
- }) : R ? /* @__PURE__ */ k(j, {
127
+ children: /* @__PURE__ */ T(i, { message: j("common.loadingPermissions", "Loading permissions…") })
128
+ }) : F ? L || V && he ? /* @__PURE__ */ T(O, {
126
129
  className: "flex items-center justify-center h-full bg-bg-surface",
127
- children: /* @__PURE__ */ k(a, {
130
+ children: /* @__PURE__ */ T(i, { message: j("vibecontrols.pages.ai.detectingAgent", "Detecting agent and plugin availability…") })
131
+ }) : R ? /* @__PURE__ */ T(O, {
132
+ className: "flex items-center justify-center h-full bg-bg-surface",
133
+ children: /* @__PURE__ */ T(a, {
128
134
  title: "Failed to load agents",
129
135
  message: R.message
130
136
  })
131
- }) : I.length === 0 ? /* @__PURE__ */ k(j, {
137
+ }) : I.length === 0 ? /* @__PURE__ */ T(O, {
132
138
  className: "flex items-center justify-center h-full bg-bg-surface p-8",
133
- children: /* @__PURE__ */ k(te, {
134
- icon: /* @__PURE__ */ k(D, { className: "size-8 text-text-secondary" }),
135
- title: P("vibecontrols.pages.ai.noActiveAgentAvailable", "No agents available"),
136
- description: P("vibecontrols.pages.ai.agentManagerRequiresAgent", "The Agent Manager needs at least one vibecontrols agent. Add one or start an existing one."),
137
- action: /* @__PURE__ */ k("button", {
139
+ children: /* @__PURE__ */ T(te, {
140
+ icon: /* @__PURE__ */ T(ue, { className: "size-8 text-text-secondary" }),
141
+ title: j("vibecontrols.pages.ai.noActiveAgentAvailable", "No agents available"),
142
+ description: j("vibecontrols.pages.ai.agentManagerRequiresAgent", "The Agent Manager needs at least one vibecontrols agent. Add one or start an existing one."),
143
+ action: /* @__PURE__ */ T("button", {
138
144
  type: "button",
139
- onClick: () => F("/agents"),
145
+ onClick: () => M("/agents"),
140
146
  className: "px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors text-sm",
141
- children: P("vibecontrols.pages.ai.goToAgents", "Go to Agents")
147
+ children: j("vibecontrols.pages.ai.goToAgents", "Go to Agents")
142
148
  })
143
149
  })
144
- }) : M === "config" ? /* @__PURE__ */ A(j, {
150
+ }) : k === "config" ? /* @__PURE__ */ E(O, {
145
151
  className: "flex flex-col h-[calc(100vh-6.5rem)] bg-bg-surface overflow-hidden",
146
- children: [/* @__PURE__ */ A("div", {
152
+ children: [/* @__PURE__ */ E("div", {
147
153
  className: "flex items-center justify-between gap-3 border-b border-border-default px-4 sm:px-6 py-3",
148
- children: [/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("p", {
154
+ children: [/* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("p", {
149
155
  className: "text-xs uppercase tracking-wide text-text-secondary",
150
- children: P("vibecontrols.pages.ai.contextLabel", "Active context")
151
- }), /* @__PURE__ */ k("h2", {
156
+ children: j("vibecontrols.pages.ai.contextLabel", "Active context")
157
+ }), /* @__PURE__ */ T("h2", {
152
158
  className: "text-sm font-semibold text-text-primary mt-0.5",
153
- children: P("vibecontrols.pages.ai.configHeading", "AI configuration")
154
- })] }), /* @__PURE__ */ A("div", {
159
+ children: j("vibecontrols.pages.ai.configHeading", "AI configuration")
160
+ })] }), /* @__PURE__ */ E("div", {
155
161
  className: "flex items-center gap-3",
156
- children: [/* @__PURE__ */ k(x, {
162
+ children: [/* @__PURE__ */ T(v, {
157
163
  aiHref: "/ai",
158
164
  activeMode: "ai"
159
- }), /* @__PURE__ */ k(d, {
160
- label: P("vibecontrols.pages.ai.agentSelectorLabel", "Agent"),
165
+ }), /* @__PURE__ */ T(f, {
166
+ label: j("vibecontrols.pages.ai.agentSelectorLabel", "Agent"),
161
167
  compact: !0
162
168
  })]
163
169
  })]
164
- }), /* @__PURE__ */ k("div", {
170
+ }), /* @__PURE__ */ T("div", {
165
171
  className: "flex-1 overflow-auto p-4 sm:p-6 space-y-6",
166
- children: /* @__PURE__ */ A(l, {
172
+ children: /* @__PURE__ */ E(u, {
167
173
  agentId: V || null,
168
- children: [/* @__PURE__ */ k(b, { agent: U }), /* @__PURE__ */ k(re, { agent: U })]
174
+ children: [/* @__PURE__ */ T(_, { agent: U }), /* @__PURE__ */ T(se, { agent: U })]
169
175
  })
170
176
  })]
171
- }) : /* @__PURE__ */ A(j, {
177
+ }) : /* @__PURE__ */ E(O, {
172
178
  className: "flex flex-col h-[calc(100vh-6.5rem)] bg-bg-surface overflow-hidden",
173
179
  children: [
174
- /* @__PURE__ */ A("div", {
180
+ /* @__PURE__ */ E("div", {
175
181
  className: "flex items-center justify-between gap-3 border-b border-border-default px-4 sm:px-6 py-3",
176
- children: [/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("p", {
182
+ children: [/* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("p", {
177
183
  className: "text-xs uppercase tracking-wide text-text-secondary",
178
- children: P("vibecontrols.pages.ai.contextLabel", "Active context")
179
- }), /* @__PURE__ */ k("h2", {
184
+ children: j("vibecontrols.pages.ai.contextLabel", "Active context")
185
+ }), /* @__PURE__ */ T("h2", {
180
186
  className: "text-sm font-semibold text-text-primary mt-0.5",
181
- children: P("vibecontrols.pages.ai.contextHeading", "AI workbench")
182
- })] }), /* @__PURE__ */ A("div", {
187
+ children: j("vibecontrols.pages.ai.contextHeading", "AI workbench")
188
+ })] }), /* @__PURE__ */ E("div", {
183
189
  className: "flex items-center gap-3",
184
- children: [/* @__PURE__ */ k(x, {
190
+ children: [/* @__PURE__ */ T(v, {
185
191
  aiHref: "/ai",
186
192
  activeMode: "ai"
187
- }), /* @__PURE__ */ k(d, {
188
- label: P("vibecontrols.pages.ai.agentSelectorLabel", "Agent"),
193
+ }), /* @__PURE__ */ T(f, {
194
+ label: j("vibecontrols.pages.ai.agentSelectorLabel", "Agent"),
189
195
  compact: !0
190
196
  })]
191
197
  })]
192
198
  }),
193
- /* @__PURE__ */ k(y, { active: "workbench" }),
194
- /* @__PURE__ */ k("div", {
199
+ /* @__PURE__ */ T(le, { active: "workbench" }),
200
+ /* @__PURE__ */ T("div", {
195
201
  className: "flex-1 min-h-0 overflow-auto p-4 sm:p-6 lg:p-0",
196
- children: /* @__PURE__ */ k(l, {
202
+ children: /* @__PURE__ */ T(u, {
197
203
  agentId: V || null,
198
- children: /* @__PURE__ */ k(c, {
204
+ children: /* @__PURE__ */ T(l, {
199
205
  agentId: V || null,
200
- onInstalled: () => void fe(),
206
+ onInstalled: () => void ve(),
201
207
  requirements: [{
202
- packages: [o],
208
+ packages: [s],
203
209
  mode: "all",
204
- eyebrow: P("vibecontrols.pages.ai.pluginRequiredEyebrow", "AI plugin required"),
205
- title: P("vibecontrols.pages.ai.coreTitle", "Install the AI orchestrator"),
206
- description: P("vibecontrols.pages.ai.coreDescription", "The AI page routes prompts and sessions through the AI orchestrator plugin on your agent. Install it to continue.")
210
+ eyebrow: j("vibecontrols.pages.ai.pluginRequiredEyebrow", "AI plugin required"),
211
+ title: j("vibecontrols.pages.ai.coreTitle", "Install the AI orchestrator"),
212
+ description: j("vibecontrols.pages.ai.coreDescription", "The AI page routes prompts and sessions through the AI orchestrator plugin on your agent. Install it to continue.")
207
213
  }, {
208
- packages: s,
214
+ packages: c,
209
215
  mode: "any",
210
- eyebrow: P("vibecontrols.pages.ai.providerEyebrow", "AI provider required"),
211
- title: P("vibecontrols.pages.ai.providerTitle", "Install at least one AI provider"),
212
- description: P("vibecontrols.pages.ai.providerDescription", "Pick the AI harness you want to use. You can install more providers later from the Plugins tab on your agent.")
216
+ eyebrow: j("vibecontrols.pages.ai.providerEyebrow", "AI provider required"),
217
+ title: j("vibecontrols.pages.ai.providerTitle", "Install at least one AI provider"),
218
+ description: j("vibecontrols.pages.ai.providerDescription", "Pick the AI harness you want to use. You can install more providers later from the Plugins tab on your agent.")
213
219
  }],
214
- children: /* @__PURE__ */ k(oe, {
215
- fallback: /* @__PURE__ */ k("div", {
220
+ children: /* @__PURE__ */ T(b, {
221
+ fallback: /* @__PURE__ */ T("div", {
216
222
  className: "flex items-center justify-center h-full",
217
- children: /* @__PURE__ */ k(i, { message: "Loading..." })
223
+ children: /* @__PURE__ */ T(i, { message: "Loading..." })
218
224
  }),
219
- children: /* @__PURE__ */ k(_, {
220
- sidebar: /* @__PURE__ */ k(v, {
225
+ children: /* @__PURE__ */ T(ae, {
226
+ sidebar: /* @__PURE__ */ T(oe, {
221
227
  agent: U,
222
- onDeleteSession: ue,
223
- onDeleteSelected: de
228
+ onDeleteSession: ge,
229
+ onDeleteSelected: _e
224
230
  }),
225
- detailPanel: J ? /* @__PURE__ */ k(ae, {
231
+ detailPanel: J ? /* @__PURE__ */ T(g, {
226
232
  sessionId: J,
227
233
  agent: U
228
234
  }) : void 0,
229
- children: /* @__PURE__ */ k(ie, { agent: U })
235
+ children: /* @__PURE__ */ T(ce, { agent: U })
230
236
  })
231
237
  })
232
238
  })
233
239
  })
234
240
  })
235
241
  ]
242
+ }) : /* @__PURE__ */ T(O, {
243
+ className: "flex items-center justify-center h-full bg-bg-surface",
244
+ children: /* @__PURE__ */ T(D, {
245
+ title: j("vibecontrols.pages.ai.denied.title", "Access Denied"),
246
+ description: j("vibecontrols.pages.ai.denied.description", "You do not have permission to view AI features.")
247
+ })
236
248
  });
237
249
  }
238
250
  //#endregion
239
- export { M as AgentManagerPage };
251
+ export { k as AgentManagerPage };
240
252
 
241
253
  //# sourceMappingURL=AgentManagerPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AgentManagerPage.js","names":[],"sources":["../../../src/pages/ai/AgentManagerPage.tsx"],"sourcesContent":["/**\n * AgentManagerPage — top-level page for the multi-session Agent Manager.\n *\n * Reads URL params (:tab, :sessionId), resolves the active agent via\n * useCachedInitialData(), auto-opens a session tab if the URL has a\n * sessionId, and renders the three-pane layout.\n */\n\nimport { Suspense, useCallback, useEffect, useMemo, useRef } from 'react';\nimport { useParams, useSearchParams } from 'react-router-dom';\nimport { useApolloClient } from '@apollo/client/react';\nimport { MessagesSquare } from 'lucide-react';\nimport { isNative, nativeNotify } from '../../utils/nativeBridge';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport {\n LoadingState,\n EmptyState,\n ErrorState,\n PluginGate,\n AgentSelector,\n RequireAgentReachable,\n} from '@/components/shared';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { usePluginAvailability } from '@/hooks/usePluginAvailability';\nimport { AgentPluginsDocument, type AgentPluginsQuery } from '@/generated/wspace-operations';\nimport { useVibeControlsStore } from '@/store/vibeControlsStore';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useAgentManagerKeyboard } from '@/hooks/useAgentManagerKeyboard';\nimport { terminateSession, bulkDeleteSessions } from '@/services/aiApi';\nimport { AgentManagerLayout } from '@/components/agent-manager/AgentManagerLayout';\nimport { AgentManagerSidebar } from '@/components/agent-manager/AgentManagerSidebar';\nimport { AgentManagerCenter } from '@/components/agent-manager/AgentManagerCenter';\nimport { AgentManagerDetailPanel } from '@/components/agent-manager/AgentManagerDetailPanel';\nimport { BridleConfigPanel } from '@/components/agent-manager/BridleConfigPanel';\nimport { ClaudeCredentialsCard } from '@/components/ai/ClaudeCredentialsCard';\nimport { AIModeToggle } from '@/components/ai/AIModeToggle';\nimport { AiSectionTabs } from '@/components/ai/AiSectionTabs';\nimport { AI_CORE_PACKAGE, AI_PROVIDER_PACKAGES } from '@/constants/pluginCatalog';\n\ninterface AgentManagerParams {\n tab?: string;\n sessionId?: string;\n}\n\nexport function AgentManagerPage() {\n const { tab: tabParam, sessionId: sessionIdParam } = useParams<\n AgentManagerParams & Record<string, string | undefined>\n >();\n const tr = useTr();\n const handleNavigate = useVibeNavigate();\n\n const { agents, loading: agentsLoading, error: agentsError } = useCachedInitialData();\n const selectedAgentId = useVibeControlsStore((s) => s.activeAgentId);\n\n // Prefer the user-selected agent from the store; fall back to the first\n // healthy one so the page works on first visit before the selector commits.\n const activeAgent = useMemo(() => {\n if (selectedAgentId) {\n const match = agents.find((a) => a.id === selectedAgentId);\n if (match) return match;\n }\n return agents.find((a) => a.isActive && a.tunnelUrl) ?? null;\n }, [agents, selectedAgentId]);\n\n const agentId = activeAgent?.id ?? '';\n // AgentRef for canonical aiApi calls — agent → profile → plugins/data.\n const { active: activeProfile } = useActiveAgentProfile(activeAgent?.id ?? null);\n const agentRef = useMemo(\n () => ({ id: agentId, profile: activeProfile }),\n [agentId, activeProfile]\n );\n const openSession = useAgentManagerStore((s) => s.openSession);\n const closeTab = useAgentManagerStore((s) => s.closeTab);\n const clearSelection = useAgentManagerStore((s) => s.clearSelection);\n const bumpSessionsRefresh = useAgentManagerStore((s) => s.bumpSessionsRefresh);\n const activeTabSessionId = useAgentManagerStore((s) => s.activeTabSessionId);\n const setActiveChatContext = useAgentManagerStore((s) => s.setActiveChatContext);\n\n // Launch \"in context\": the /ai route accepts ?vibeId=…&contextLevel=vibe\n // (from a vibe's \"Open AI chat\") or ?contextLevel=agent. This sets the active\n // bucket so new sessions are tagged + the sidebar list is filtered to it.\n const [searchParams] = useSearchParams();\n useEffect(() => {\n const vibeIdParam = searchParams.get('vibeId');\n setActiveChatContext({\n contextLevel: vibeIdParam ? 'vibe' : 'agent',\n vibeId: vibeIdParam ?? null,\n });\n }, [searchParams, setActiveChatContext]);\n\n // Pre-fetch plugin availability at the page level so the detection phase\n // overlaps with the agents query's resolution. This collapses the two\n // sequential loading states (\"Loading agents...\" → \"Checking plugin\n // availability...\") into one unified wait, eliminating the flicker the\n // user saw between them.\n const detectionPackages = useMemo(() => [AI_CORE_PACKAGE, ...AI_PROVIDER_PACKAGES], []);\n // Plugins are agent-wide (BOFF-2612). `activeProfile` is still resolved\n // above for non-plugin concerns (aiApi agentRef).\n const { initialLoading: pluginsInitialLoading, refetch: refetchPlugins } = usePluginAvailability(\n detectionPackages,\n agentId || null\n );\n\n const apollo = useApolloClient();\n // Guards onInstalled against re-entrancy if the gate fires the transition\n // more than once while a poll is still in flight.\n const completingInstallRef = useRef(false);\n\n // Auto-open session from URL param\n useEffect(() => {\n if (sessionIdParam && agentId) {\n openSession(sessionIdParam, `Session ${sessionIdParam.slice(0, 8)}`);\n }\n }, [sessionIdParam, agentId, openSession]);\n\n const handleDeleteSession = useCallback(\n async (sessionId: string) => {\n if (!agentId) return;\n try {\n await terminateSession(agentRef, sessionId);\n closeTab(sessionId);\n bumpSessionsRefresh();\n if (isNative()) void nativeNotify('success');\n } catch {\n if (isNative()) void nativeNotify('error');\n }\n },\n [agentId, agentRef, bumpSessionsRefresh, closeTab]\n );\n\n const handleDeleteSelected = useCallback(\n async (sessionIds: string[]) => {\n if (!agentId) return;\n try {\n await bulkDeleteSessions(agentRef, sessionIds);\n sessionIds.forEach((sessionId) => closeTab(sessionId));\n clearSelection();\n bumpSessionsRefresh();\n if (isNative()) void nativeNotify('success');\n } catch {\n if (isNative()) void nativeNotify('error');\n }\n },\n [agentId, agentRef, bumpSessionsRefresh, clearSelection, closeTab]\n );\n\n // Smart completion after the first provider install resolves the gate.\n // Replaces the old window.location.reload() (BOFF-2671): instead of nuking\n // the SPA, we make sure every consumer of `agentPlugins` (gate,\n // AgentManagerCenter, harness/provider selectors) sees the freshly-installed\n // provider. The agent-side npm install is async (~10–30s) and the gate only\n // fires this once it has already detected the provider, but the surrounding\n // surfaces read the Apollo cache directly — so we refetch, then poll\n // network-only until at least one provider package is present in the cached\n // list, capping the wait so we never spin forever.\n const handleProviderInstalled = useCallback(async () => {\n if (completingInstallRef.current || !agentId) return;\n completingInstallRef.current = true;\n // Reads the authoritative provider-present state from the Apollo cache,\n // which refetchPlugins() / the network-only poll both write through. Avoids\n // a stale React-state closure (installedPlugins captured at callback build).\n const providerPresentInCache = (): boolean => {\n try {\n const cached = apollo.readQuery<AgentPluginsQuery>({\n query: AgentPluginsDocument,\n variables: { agentId },\n });\n const names = new Set((cached?.agentPlugins?.installed ?? []).map((p) => p.packageName));\n return AI_PROVIDER_PACKAGES.some((pkg) => names.has(pkg));\n } catch {\n return false;\n }\n };\n try {\n // Fast path: the optimistic + subscription-driven cache may already show a\n // provider. Refetch once to write the authoritative list into the cache.\n await refetchPlugins();\n if (providerPresentInCache()) return;\n\n // Slow path: poll the agent directly until the provider lands or we give\n // up (15 attempts × ~2s ≈ 30s, matching the worst-case npm install).\n for (let attempt = 0; attempt < 15; attempt += 1) {\n await new Promise((resolve) => setTimeout(resolve, 2000));\n try {\n const { data } = await apollo.query<AgentPluginsQuery>({\n query: AgentPluginsDocument,\n variables: { agentId },\n fetchPolicy: 'network-only',\n });\n const installedList = data?.agentPlugins?.installed ?? [];\n const names = new Set(installedList.map((p) => p.packageName));\n if (AI_PROVIDER_PACKAGES.some((pkg) => names.has(pkg))) break;\n } catch (err) {\n // Transient agent-not-ready errors are expected mid-install; keep\n // polling. Surface only for debuggability.\n console.warn('[ai] provider poll attempt failed', err);\n }\n }\n // Final refetch so the hook's installed map + cache reflect the result.\n await refetchPlugins();\n } finally {\n completingInstallRef.current = false;\n }\n }, [agentId, apollo, refetchPlugins]);\n\n // Activate keyboard shortcuts (Ctrl+Shift+N, Ctrl+K, Ctrl+F, Escape)\n useAgentManagerKeyboard();\n\n // Single unified wait: show one LoadingState while either the agents\n // query or the plugin-availability probe is still in flight. Prevents\n // the two-step \"Loading agents...\" → \"Checking plugin availability...\"\n // cascade. `agentId && pluginsInitialLoading` also catches the case\n // where agents resolved but the plugin probe hasn't fired/settled yet.\n if (agentsLoading || (agentId && pluginsInitialLoading)) {\n return (\n <MotionPage className=\"flex items-center justify-center h-full bg-bg-surface\">\n <LoadingState\n message={tr(\n 'vibecontrols.pages.ai.detectingAgent',\n 'Detecting agent and plugin availability…'\n )}\n />\n </MotionPage>\n );\n }\n\n if (agentsError) {\n return (\n <MotionPage className=\"flex items-center justify-center h-full bg-bg-surface\">\n <ErrorState title=\"Failed to load agents\" message={agentsError.message} />\n </MotionPage>\n );\n }\n\n if (agents.length === 0) {\n return (\n <MotionPage className=\"flex items-center justify-center h-full bg-bg-surface p-8\">\n <EmptyState\n icon={<MessagesSquare className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.pages.ai.noActiveAgentAvailable', 'No agents available')}\n description={tr(\n 'vibecontrols.pages.ai.agentManagerRequiresAgent',\n 'The Agent Manager needs at least one vibecontrols agent. Add one or start an existing one.'\n )}\n action={\n <button\n type=\"button\"\n onClick={() => handleNavigate('/agents')}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors text-sm\"\n >\n {tr('vibecontrols.pages.ai.goToAgents', 'Go to Agents')}\n </button>\n }\n />\n </MotionPage>\n );\n }\n\n if (tabParam === 'config') {\n return (\n <MotionPage className=\"flex flex-col h-[calc(100vh-6.5rem)] bg-bg-surface overflow-hidden\">\n <div className=\"flex items-center justify-between gap-3 border-b border-border-default px-4 sm:px-6 py-3\">\n <div>\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">\n {tr('vibecontrols.pages.ai.contextLabel', 'Active context')}\n </p>\n <h2 className=\"text-sm font-semibold text-text-primary mt-0.5\">\n {tr('vibecontrols.pages.ai.configHeading', 'AI configuration')}\n </h2>\n </div>\n <div className=\"flex items-center gap-3\">\n <AIModeToggle aiHref=\"/ai\" activeMode=\"ai\" />\n <AgentSelector\n label={tr('vibecontrols.pages.ai.agentSelectorLabel', 'Agent')}\n compact\n />\n </div>\n </div>\n\n <div className=\"flex-1 overflow-auto p-4 sm:p-6 space-y-6\">\n <RequireAgentReachable agentId={agentId || null}>\n <ClaudeCredentialsCard agent={agentRef} />\n <BridleConfigPanel agent={agentRef} />\n </RequireAgentReachable>\n </div>\n </MotionPage>\n );\n }\n\n return (\n <MotionPage className=\"flex flex-col h-[calc(100vh-6.5rem)] bg-bg-surface overflow-hidden\">\n <div className=\"flex items-center justify-between gap-3 border-b border-border-default px-4 sm:px-6 py-3\">\n <div>\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">\n {tr('vibecontrols.pages.ai.contextLabel', 'Active context')}\n </p>\n <h2 className=\"text-sm font-semibold text-text-primary mt-0.5\">\n {tr('vibecontrols.pages.ai.contextHeading', 'AI workbench')}\n </h2>\n </div>\n <div className=\"flex items-center gap-3\">\n {/* Plan toggle navigates to the canonical /ai-tools/plan\n workspace; the AI side stays on this AgentManagerPage. */}\n <AIModeToggle aiHref=\"/ai\" activeMode=\"ai\" />\n <AgentSelector label={tr('vibecontrols.pages.ai.agentSelectorLabel', 'Agent')} compact />\n </div>\n </div>\n\n <AiSectionTabs active=\"workbench\" />\n\n <div className=\"flex-1 min-h-0 overflow-auto p-4 sm:p-6 lg:p-0\">\n <RequireAgentReachable agentId={agentId || null}>\n <PluginGate\n agentId={agentId || null}\n // Smart completion instead of window.location.reload() (BOFF-2671).\n // PluginGate fires this on the unsatisfied → satisfied transition,\n // i.e. once the first provider is detected. We then refetch +\n // network-only-poll the agent's plugin list so the gate's children\n // (AgentManagerCenter and every provider/harness selector) read the\n // freshly-installed provider from the Apollo cache — no full reload,\n // no empty chat surface waiting on a manual refresh.\n onInstalled={() => void handleProviderInstalled()}\n requirements={[\n {\n packages: [AI_CORE_PACKAGE],\n mode: 'all',\n eyebrow: tr('vibecontrols.pages.ai.pluginRequiredEyebrow', 'AI plugin required'),\n title: tr('vibecontrols.pages.ai.coreTitle', 'Install the AI orchestrator'),\n description: tr(\n 'vibecontrols.pages.ai.coreDescription',\n 'The AI page routes prompts and sessions through the AI orchestrator plugin on your agent. Install it to continue.'\n ),\n },\n {\n packages: AI_PROVIDER_PACKAGES,\n mode: 'any',\n eyebrow: tr('vibecontrols.pages.ai.providerEyebrow', 'AI provider required'),\n title: tr(\n 'vibecontrols.pages.ai.providerTitle',\n 'Install at least one AI provider'\n ),\n description: tr(\n 'vibecontrols.pages.ai.providerDescription',\n 'Pick the AI harness you want to use. You can install more providers later from the Plugins tab on your agent.'\n ),\n },\n ]}\n >\n <Suspense\n fallback={\n <div className=\"flex items-center justify-center h-full\">\n <LoadingState message=\"Loading...\" />\n </div>\n }\n >\n <AgentManagerLayout\n sidebar={\n <AgentManagerSidebar\n agent={agentRef}\n onDeleteSession={handleDeleteSession}\n onDeleteSelected={handleDeleteSelected}\n />\n }\n detailPanel={\n activeTabSessionId ? (\n <AgentManagerDetailPanel sessionId={activeTabSessionId} agent={agentRef} />\n ) : undefined\n }\n >\n <AgentManagerCenter agent={agentRef} />\n </AgentManagerLayout>\n </Suspense>\n </PluginGate>\n </RequireAgentReachable>\n </div>\n </MotionPage>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentManagerPage.js","names":[],"sources":["../../../src/pages/ai/AgentManagerPage.tsx"],"sourcesContent":["/**\n * AgentManagerPage — top-level page for the multi-session Agent Manager.\n *\n * Reads URL params (:tab, :sessionId), resolves the active agent via\n * useCachedInitialData(), auto-opens a session tab if the URL has a\n * sessionId, and renders the three-pane layout.\n */\n\nimport { Suspense, useCallback, useEffect, useMemo, useRef } from 'react';\nimport { useParams, useSearchParams } from 'react-router-dom';\nimport { useApolloClient } from '@apollo/client/react';\nimport { MessagesSquare } from 'lucide-react';\nimport { isNative, nativeNotify } from '../../utils/nativeBridge';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport {\n LoadingState,\n EmptyState,\n ErrorState,\n PluginGate,\n AgentSelector,\n RequireAgentReachable,\n} from '@/components/shared';\nimport { AccessDenied } from '@burdenoff/fe-libs/shared/components';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { usePluginAvailability } from '@/hooks/usePluginAvailability';\nimport { AgentPluginsDocument, type AgentPluginsQuery } from '@/generated/wspace-operations';\nimport { useVibeControlsStore } from '@/store/vibeControlsStore';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useAgentManagerKeyboard } from '@/hooks/useAgentManagerKeyboard';\nimport { terminateSession, bulkDeleteSessions } from '@/services/aiApi';\nimport { AgentManagerLayout } from '@/components/agent-manager/AgentManagerLayout';\nimport { AgentManagerSidebar } from '@/components/agent-manager/AgentManagerSidebar';\nimport { AgentManagerCenter } from '@/components/agent-manager/AgentManagerCenter';\nimport { AgentManagerDetailPanel } from '@/components/agent-manager/AgentManagerDetailPanel';\nimport { BridleConfigPanel } from '@/components/agent-manager/BridleConfigPanel';\nimport { ClaudeCredentialsCard } from '@/components/ai/ClaudeCredentialsCard';\nimport { AIModeToggle } from '@/components/ai/AIModeToggle';\nimport { AiSectionTabs } from '@/components/ai/AiSectionTabs';\nimport { AI_CORE_PACKAGE, AI_PROVIDER_PACKAGES } from '@/constants/pluginCatalog';\n\ninterface AgentManagerParams {\n tab?: string;\n sessionId?: string;\n}\n\nexport function AgentManagerPage() {\n const { tab: tabParam, sessionId: sessionIdParam } = useParams<\n AgentManagerParams & Record<string, string | undefined>\n >();\n const tr = useTr();\n const handleNavigate = useVibeNavigate();\n // Agent-centric page — gate on `agent:read` (defense-in-depth).\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const canReadAgents = hasPermission(VIBE_PERMISSIONS.AGENT_READ);\n\n const { agents, loading: agentsLoading, error: agentsError } = useCachedInitialData();\n const selectedAgentId = useVibeControlsStore((s) => s.activeAgentId);\n\n // Prefer the user-selected agent from the store; fall back to the first\n // healthy one so the page works on first visit before the selector commits.\n const activeAgent = useMemo(() => {\n if (selectedAgentId) {\n const match = agents.find((a) => a.id === selectedAgentId);\n if (match) return match;\n }\n return agents.find((a) => a.isActive && a.tunnelUrl) ?? null;\n }, [agents, selectedAgentId]);\n\n const agentId = activeAgent?.id ?? '';\n // AgentRef for canonical aiApi calls — agent → profile → plugins/data.\n const { active: activeProfile } = useActiveAgentProfile(activeAgent?.id ?? null);\n const agentRef = useMemo(\n () => ({ id: agentId, profile: activeProfile }),\n [agentId, activeProfile]\n );\n const openSession = useAgentManagerStore((s) => s.openSession);\n const closeTab = useAgentManagerStore((s) => s.closeTab);\n const clearSelection = useAgentManagerStore((s) => s.clearSelection);\n const bumpSessionsRefresh = useAgentManagerStore((s) => s.bumpSessionsRefresh);\n const activeTabSessionId = useAgentManagerStore((s) => s.activeTabSessionId);\n const setActiveChatContext = useAgentManagerStore((s) => s.setActiveChatContext);\n\n // Launch \"in context\": the /ai route accepts ?vibeId=…&contextLevel=vibe\n // (from a vibe's \"Open AI chat\") or ?contextLevel=agent. This sets the active\n // bucket so new sessions are tagged + the sidebar list is filtered to it.\n const [searchParams] = useSearchParams();\n useEffect(() => {\n const vibeIdParam = searchParams.get('vibeId');\n setActiveChatContext({\n contextLevel: vibeIdParam ? 'vibe' : 'agent',\n vibeId: vibeIdParam ?? null,\n });\n }, [searchParams, setActiveChatContext]);\n\n // Pre-fetch plugin availability at the page level so the detection phase\n // overlaps with the agents query's resolution. This collapses the two\n // sequential loading states (\"Loading agents...\" → \"Checking plugin\n // availability...\") into one unified wait, eliminating the flicker the\n // user saw between them.\n const detectionPackages = useMemo(() => [AI_CORE_PACKAGE, ...AI_PROVIDER_PACKAGES], []);\n // Plugins are agent-wide (BOFF-2612). `activeProfile` is still resolved\n // above for non-plugin concerns (aiApi agentRef).\n const { initialLoading: pluginsInitialLoading, refetch: refetchPlugins } = usePluginAvailability(\n detectionPackages,\n agentId || null\n );\n\n const apollo = useApolloClient();\n // Guards onInstalled against re-entrancy if the gate fires the transition\n // more than once while a poll is still in flight.\n const completingInstallRef = useRef(false);\n\n // Auto-open session from URL param\n useEffect(() => {\n if (sessionIdParam && agentId) {\n openSession(sessionIdParam, `Session ${sessionIdParam.slice(0, 8)}`);\n }\n }, [sessionIdParam, agentId, openSession]);\n\n const handleDeleteSession = useCallback(\n async (sessionId: string) => {\n if (!agentId) return;\n try {\n await terminateSession(agentRef, sessionId);\n closeTab(sessionId);\n bumpSessionsRefresh();\n if (isNative()) void nativeNotify('success');\n } catch {\n if (isNative()) void nativeNotify('error');\n }\n },\n [agentId, agentRef, bumpSessionsRefresh, closeTab]\n );\n\n const handleDeleteSelected = useCallback(\n async (sessionIds: string[]) => {\n if (!agentId) return;\n try {\n await bulkDeleteSessions(agentRef, sessionIds);\n sessionIds.forEach((sessionId) => closeTab(sessionId));\n clearSelection();\n bumpSessionsRefresh();\n if (isNative()) void nativeNotify('success');\n } catch {\n if (isNative()) void nativeNotify('error');\n }\n },\n [agentId, agentRef, bumpSessionsRefresh, clearSelection, closeTab]\n );\n\n // Smart completion after the first provider install resolves the gate.\n // Replaces the old window.location.reload() (BOFF-2671): instead of nuking\n // the SPA, we make sure every consumer of `agentPlugins` (gate,\n // AgentManagerCenter, harness/provider selectors) sees the freshly-installed\n // provider. The agent-side npm install is async (~10–30s) and the gate only\n // fires this once it has already detected the provider, but the surrounding\n // surfaces read the Apollo cache directly — so we refetch, then poll\n // network-only until at least one provider package is present in the cached\n // list, capping the wait so we never spin forever.\n const handleProviderInstalled = useCallback(async () => {\n if (completingInstallRef.current || !agentId) return;\n completingInstallRef.current = true;\n // Reads the authoritative provider-present state from the Apollo cache,\n // which refetchPlugins() / the network-only poll both write through. Avoids\n // a stale React-state closure (installedPlugins captured at callback build).\n const providerPresentInCache = (): boolean => {\n try {\n const cached = apollo.readQuery<AgentPluginsQuery>({\n query: AgentPluginsDocument,\n variables: { agentId },\n });\n const names = new Set((cached?.agentPlugins?.installed ?? []).map((p) => p.packageName));\n return AI_PROVIDER_PACKAGES.some((pkg) => names.has(pkg));\n } catch {\n return false;\n }\n };\n try {\n // Fast path: the optimistic + subscription-driven cache may already show a\n // provider. Refetch once to write the authoritative list into the cache.\n await refetchPlugins();\n if (providerPresentInCache()) return;\n\n // Slow path: poll the agent directly until the provider lands or we give\n // up (15 attempts × ~2s ≈ 30s, matching the worst-case npm install).\n for (let attempt = 0; attempt < 15; attempt += 1) {\n await new Promise((resolve) => setTimeout(resolve, 2000));\n try {\n const { data } = await apollo.query<AgentPluginsQuery>({\n query: AgentPluginsDocument,\n variables: { agentId },\n fetchPolicy: 'network-only',\n });\n const installedList = data?.agentPlugins?.installed ?? [];\n const names = new Set(installedList.map((p) => p.packageName));\n if (AI_PROVIDER_PACKAGES.some((pkg) => names.has(pkg))) break;\n } catch (err) {\n // Transient agent-not-ready errors are expected mid-install; keep\n // polling. Surface only for debuggability.\n console.warn('[ai] provider poll attempt failed', err);\n }\n }\n // Final refetch so the hook's installed map + cache reflect the result.\n await refetchPlugins();\n } finally {\n completingInstallRef.current = false;\n }\n }, [agentId, apollo, refetchPlugins]);\n\n // Activate keyboard shortcuts (Ctrl+Shift+N, Ctrl+K, Ctrl+F, Escape)\n useAgentManagerKeyboard();\n\n if (permissionsLoading) {\n return (\n <MotionPage className=\"flex items-center justify-center h-full bg-bg-surface\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions…')} />\n </MotionPage>\n );\n }\n\n if (!canReadAgents) {\n return (\n <MotionPage className=\"flex items-center justify-center h-full bg-bg-surface\">\n <AccessDenied\n title={tr('vibecontrols.pages.ai.denied.title', 'Access Denied')}\n description={tr(\n 'vibecontrols.pages.ai.denied.description',\n 'You do not have permission to view AI features.'\n )}\n />\n </MotionPage>\n );\n }\n\n // Single unified wait: show one LoadingState while either the agents\n // query or the plugin-availability probe is still in flight. Prevents\n // the two-step \"Loading agents...\" → \"Checking plugin availability...\"\n // cascade. `agentId && pluginsInitialLoading` also catches the case\n // where agents resolved but the plugin probe hasn't fired/settled yet.\n if (agentsLoading || (agentId && pluginsInitialLoading)) {\n return (\n <MotionPage className=\"flex items-center justify-center h-full bg-bg-surface\">\n <LoadingState\n message={tr(\n 'vibecontrols.pages.ai.detectingAgent',\n 'Detecting agent and plugin availability…'\n )}\n />\n </MotionPage>\n );\n }\n\n if (agentsError) {\n return (\n <MotionPage className=\"flex items-center justify-center h-full bg-bg-surface\">\n <ErrorState title=\"Failed to load agents\" message={agentsError.message} />\n </MotionPage>\n );\n }\n\n if (agents.length === 0) {\n return (\n <MotionPage className=\"flex items-center justify-center h-full bg-bg-surface p-8\">\n <EmptyState\n icon={<MessagesSquare className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.pages.ai.noActiveAgentAvailable', 'No agents available')}\n description={tr(\n 'vibecontrols.pages.ai.agentManagerRequiresAgent',\n 'The Agent Manager needs at least one vibecontrols agent. Add one or start an existing one.'\n )}\n action={\n <button\n type=\"button\"\n onClick={() => handleNavigate('/agents')}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors text-sm\"\n >\n {tr('vibecontrols.pages.ai.goToAgents', 'Go to Agents')}\n </button>\n }\n />\n </MotionPage>\n );\n }\n\n if (tabParam === 'config') {\n return (\n <MotionPage className=\"flex flex-col h-[calc(100vh-6.5rem)] bg-bg-surface overflow-hidden\">\n <div className=\"flex items-center justify-between gap-3 border-b border-border-default px-4 sm:px-6 py-3\">\n <div>\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">\n {tr('vibecontrols.pages.ai.contextLabel', 'Active context')}\n </p>\n <h2 className=\"text-sm font-semibold text-text-primary mt-0.5\">\n {tr('vibecontrols.pages.ai.configHeading', 'AI configuration')}\n </h2>\n </div>\n <div className=\"flex items-center gap-3\">\n <AIModeToggle aiHref=\"/ai\" activeMode=\"ai\" />\n <AgentSelector\n label={tr('vibecontrols.pages.ai.agentSelectorLabel', 'Agent')}\n compact\n />\n </div>\n </div>\n\n <div className=\"flex-1 overflow-auto p-4 sm:p-6 space-y-6\">\n <RequireAgentReachable agentId={agentId || null}>\n <ClaudeCredentialsCard agent={agentRef} />\n <BridleConfigPanel agent={agentRef} />\n </RequireAgentReachable>\n </div>\n </MotionPage>\n );\n }\n\n return (\n <MotionPage className=\"flex flex-col h-[calc(100vh-6.5rem)] bg-bg-surface overflow-hidden\">\n <div className=\"flex items-center justify-between gap-3 border-b border-border-default px-4 sm:px-6 py-3\">\n <div>\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">\n {tr('vibecontrols.pages.ai.contextLabel', 'Active context')}\n </p>\n <h2 className=\"text-sm font-semibold text-text-primary mt-0.5\">\n {tr('vibecontrols.pages.ai.contextHeading', 'AI workbench')}\n </h2>\n </div>\n <div className=\"flex items-center gap-3\">\n {/* Plan toggle navigates to the canonical /ai-tools/plan\n workspace; the AI side stays on this AgentManagerPage. */}\n <AIModeToggle aiHref=\"/ai\" activeMode=\"ai\" />\n <AgentSelector label={tr('vibecontrols.pages.ai.agentSelectorLabel', 'Agent')} compact />\n </div>\n </div>\n\n <AiSectionTabs active=\"workbench\" />\n\n <div className=\"flex-1 min-h-0 overflow-auto p-4 sm:p-6 lg:p-0\">\n <RequireAgentReachable agentId={agentId || null}>\n <PluginGate\n agentId={agentId || null}\n // Smart completion instead of window.location.reload() (BOFF-2671).\n // PluginGate fires this on the unsatisfied → satisfied transition,\n // i.e. once the first provider is detected. We then refetch +\n // network-only-poll the agent's plugin list so the gate's children\n // (AgentManagerCenter and every provider/harness selector) read the\n // freshly-installed provider from the Apollo cache — no full reload,\n // no empty chat surface waiting on a manual refresh.\n onInstalled={() => void handleProviderInstalled()}\n requirements={[\n {\n packages: [AI_CORE_PACKAGE],\n mode: 'all',\n eyebrow: tr('vibecontrols.pages.ai.pluginRequiredEyebrow', 'AI plugin required'),\n title: tr('vibecontrols.pages.ai.coreTitle', 'Install the AI orchestrator'),\n description: tr(\n 'vibecontrols.pages.ai.coreDescription',\n 'The AI page routes prompts and sessions through the AI orchestrator plugin on your agent. Install it to continue.'\n ),\n },\n {\n packages: AI_PROVIDER_PACKAGES,\n mode: 'any',\n eyebrow: tr('vibecontrols.pages.ai.providerEyebrow', 'AI provider required'),\n title: tr(\n 'vibecontrols.pages.ai.providerTitle',\n 'Install at least one AI provider'\n ),\n description: tr(\n 'vibecontrols.pages.ai.providerDescription',\n 'Pick the AI harness you want to use. You can install more providers later from the Plugins tab on your agent.'\n ),\n },\n ]}\n >\n <Suspense\n fallback={\n <div className=\"flex items-center justify-center h-full\">\n <LoadingState message=\"Loading...\" />\n </div>\n }\n >\n <AgentManagerLayout\n sidebar={\n <AgentManagerSidebar\n agent={agentRef}\n onDeleteSession={handleDeleteSession}\n onDeleteSelected={handleDeleteSelected}\n />\n }\n detailPanel={\n activeTabSessionId ? (\n <AgentManagerDetailPanel sessionId={activeTabSessionId} agent={agentRef} />\n ) : undefined\n }\n >\n <AgentManagerCenter agent={agentRef} />\n </AgentManagerLayout>\n </Suspense>\n </PluginGate>\n </RequireAgentReachable>\n </div>\n </MotionPage>\n );\n}\n"],"mappings":"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"}