@burdenoff/microfe-vibecontrols 2026.601.2 → 2026.601.3

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.
@@ -2,84 +2,95 @@ import { AgentPluginsDocument as e } from "../../generated/wspace-operations.js"
2
2
  import { useTr as t } from "../../shared/hooks/useTr.js";
3
3
  import { useVibeNavigate as n } from "../../providers/VibeControlsProvider.js";
4
4
  import { useVibeControlsStore as r } from "../../store/vibeControlsStore.js";
5
- import i from "../../hooks/useCachedInitialData.js";
6
- import { LoadingState as a } from "../../components/shared/LoadingState.js";
7
- import { ErrorState as ee } from "../../components/shared/ErrorState.js";
8
- import { EmptyState as o } from "../../components/shared/EmptyState.js";
9
- import { usePluginAvailability as s } from "../../hooks/usePluginAvailability.js";
10
- import { AI_CORE_PACKAGE as c, AI_PROVIDER_PACKAGES as l } from "../../constants/pluginCatalog.js";
11
- import { PluginGate as u } from "../../components/shared/PluginGate.js";
12
- import { RequireAgentReachable as d } from "../../components/shared/RequireAgentReachable.js";
13
- import { useActiveAgentProfile as f } from "../../hooks/useActiveAgentProfile.js";
14
- import { AgentSelector as p } from "../../components/shared/AgentSelector.js";
5
+ import ee from "../../hooks/useCachedInitialData.js";
6
+ import { LoadingState as i } from "../../components/shared/LoadingState.js";
7
+ import { ErrorState as a } from "../../components/shared/ErrorState.js";
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";
15
15
  import "../../components/shared/index.js";
16
- import { isNative as m, nativeNotify as h } from "../../utils/nativeBridge.js";
17
- import { bulkDeleteSessions as g, terminateSession as te } from "../../services/aiApi.js";
18
- import { useAgentManagerStore as _ } from "../../store/agentManagerStore.js";
19
- import { AgentManagerLayout as ne } from "../../components/agent-manager/AgentManagerLayout.js";
20
- import { AgentManagerSidebar as re } from "../../components/agent-manager/AgentManagerSidebar.js";
21
- import { BridleConfigPanel as ie } from "../../components/agent-manager/BridleConfigPanel.js";
22
- import { AgentManagerCenter as v } from "../../components/agent-manager/AgentManagerCenter.js";
23
- import { AgentManagerDetailPanel as y } from "../../components/agent-manager/AgentManagerDetailPanel.js";
24
- import { AiSectionTabs as b } from "../../components/ai/AiSectionTabs.js";
25
- import { ClaudeCredentialsCard as x } from "../../components/ai/ClaudeCredentialsCard.js";
26
- import { AIModeToggle as S } from "../../components/ai/AIModeToggle.js";
27
- import { useAgentManagerKeyboard as C } from "../../hooks/useAgentManagerKeyboard.js";
28
- import { Suspense as w, useCallback as T, useEffect as E, useMemo as D, useRef as O } from "react";
29
- import { MessagesSquare as k } from "lucide-react";
30
- import { useParams as A, useSearchParams as ae } from "react-router-dom";
31
- import { useApolloClient as oe } from "@apollo/client/react";
32
- import { jsx as j, jsxs as M } from "react/jsx-runtime";
33
- import { MotionPage as N } from "@burdenoff/fe-libs/shared/motion";
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";
34
34
  //#region src/pages/ai/AgentManagerPage.tsx
35
- function P() {
36
- let { tab: P, sessionId: F } = A(), I = t(), L = n(), { agents: R, loading: z, error: B } = i(), V = r((e) => e.activeAgentId), H = D(() => {
37
- if (V) {
38
- let e = R.find((e) => e.id === V);
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(() => {
37
+ if (z) {
38
+ let e = I.find((e) => e.id === z);
39
39
  if (e) return e;
40
40
  }
41
- return R.find((e) => e.isActive && e.tunnelUrl) ?? null;
42
- }, [R, V]), U = H?.id ?? "", { active: W } = f(H?.id ?? null), G = D(() => ({
43
- id: U,
44
- profile: W
45
- }), [U, W]), K = _((e) => e.openSession), q = _((e) => e.activeTabSessionId), J = _((e) => e.setActiveChatContext), [Y] = ae();
46
- E(() => {
47
- let e = Y.get("vibeId");
48
- J({
41
+ return I.find((e) => e.isActive && e.tunnelUrl) ?? null;
42
+ }, [I, z]), V = B?.id ?? "", { active: H } = u(B?.id ?? null), U = T(() => ({
43
+ id: V,
44
+ 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(() => {
47
+ let e = X.get("vibeId");
48
+ Y({
49
49
  contextLevel: e ? "vibe" : "agent",
50
50
  vibeId: e ?? null
51
51
  });
52
- }, [Y, J]);
53
- let { initialLoading: X, refetch: Z } = s(D(() => [c, ...l], []), U || null), Q = oe(), $ = O(!1);
54
- E(() => {
55
- F && U && K(F, `Session ${F.slice(0, 8)}`);
52
+ }, [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
56
  }, [
57
- F,
58
- U,
59
- K
57
+ N,
58
+ V,
59
+ W
60
60
  ]);
61
- let se = T(async (e) => {
62
- if (U) try {
63
- await te(G, e), m() && h("success");
61
+ let ue = C(async (e) => {
62
+ if (V) try {
63
+ await h(U, e), G(e), q(), f() && p("success");
64
64
  } catch {
65
- m() && h("error");
65
+ f() && p("error");
66
66
  }
67
- }, [G]), ce = T(async (e) => {
68
- if (U) try {
69
- await g(G, e), m() && h("success");
67
+ }, [
68
+ V,
69
+ U,
70
+ q,
71
+ G
72
+ ]), de = C(async (e) => {
73
+ if (V) try {
74
+ await m(U, e), e.forEach((e) => G(e)), K(), q(), f() && p("success");
70
75
  } catch {
71
- m() && h("error");
76
+ f() && p("error");
72
77
  }
73
- }, [G]), le = T(async () => {
74
- if ($.current || !U) return;
78
+ }, [
79
+ V,
80
+ U,
81
+ q,
82
+ K,
83
+ G
84
+ ]), fe = C(async () => {
85
+ if ($.current || !V) return;
75
86
  $.current = !0;
76
87
  let t = () => {
77
88
  try {
78
89
  let t = Q.readQuery({
79
90
  query: e,
80
- variables: { agentId: U }
91
+ variables: { agentId: V }
81
92
  }), n = new Set((t?.agentPlugins?.installed ?? []).map((e) => e.packageName));
82
- return l.some((e) => n.has(e));
93
+ return s.some((e) => n.has(e));
83
94
  } catch {
84
95
  return !1;
85
96
  }
@@ -91,10 +102,10 @@ function P() {
91
102
  try {
92
103
  let { data: t } = await Q.query({
93
104
  query: e,
94
- variables: { agentId: U },
105
+ variables: { agentId: V },
95
106
  fetchPolicy: "network-only"
96
107
  }), n = t?.agentPlugins?.installed ?? [], r = new Set(n.map((e) => e.packageName));
97
- if (l.some((e) => r.has(e))) break;
108
+ if (s.some((e) => r.has(e))) break;
98
109
  } catch (e) {
99
110
  console.warn("[ai] provider poll attempt failed", e);
100
111
  }
@@ -104,118 +115,118 @@ function P() {
104
115
  $.current = !1;
105
116
  }
106
117
  }, [
107
- U,
118
+ V,
108
119
  Q,
109
120
  Z
110
121
  ]);
111
- return C(), z || U && X ? /* @__PURE__ */ j(N, {
122
+ return S(), L || V && le ? /* @__PURE__ */ k(j, {
112
123
  className: "flex items-center justify-center h-full bg-bg-surface",
113
- children: /* @__PURE__ */ j(a, { message: I("vibecontrols.pages.ai.detectingAgent", "Detecting agent and plugin availability…") })
114
- }) : B ? /* @__PURE__ */ j(N, {
124
+ children: /* @__PURE__ */ k(i, { message: P("vibecontrols.pages.ai.detectingAgent", "Detecting agent and plugin availability…") })
125
+ }) : R ? /* @__PURE__ */ k(j, {
115
126
  className: "flex items-center justify-center h-full bg-bg-surface",
116
- children: /* @__PURE__ */ j(ee, {
127
+ children: /* @__PURE__ */ k(a, {
117
128
  title: "Failed to load agents",
118
- message: B.message
129
+ message: R.message
119
130
  })
120
- }) : R.length === 0 ? /* @__PURE__ */ j(N, {
131
+ }) : I.length === 0 ? /* @__PURE__ */ k(j, {
121
132
  className: "flex items-center justify-center h-full bg-bg-surface p-8",
122
- children: /* @__PURE__ */ j(o, {
123
- icon: /* @__PURE__ */ j(k, { className: "size-8 text-text-secondary" }),
124
- title: I("vibecontrols.pages.ai.noActiveAgentAvailable", "No agents available"),
125
- description: I("vibecontrols.pages.ai.agentManagerRequiresAgent", "The Agent Manager needs at least one vibecontrols agent. Add one or start an existing one."),
126
- action: /* @__PURE__ */ j("button", {
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", {
127
138
  type: "button",
128
- onClick: () => L("/agents"),
139
+ onClick: () => F("/agents"),
129
140
  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",
130
- children: I("vibecontrols.pages.ai.goToAgents", "Go to Agents")
141
+ children: P("vibecontrols.pages.ai.goToAgents", "Go to Agents")
131
142
  })
132
143
  })
133
- }) : P === "config" ? /* @__PURE__ */ M(N, {
144
+ }) : M === "config" ? /* @__PURE__ */ A(j, {
134
145
  className: "flex flex-col h-[calc(100vh-6.5rem)] bg-bg-surface overflow-hidden",
135
- children: [/* @__PURE__ */ M("div", {
146
+ children: [/* @__PURE__ */ A("div", {
136
147
  className: "flex items-center justify-between gap-3 border-b border-border-default px-4 sm:px-6 py-3",
137
- children: [/* @__PURE__ */ M("div", { children: [/* @__PURE__ */ j("p", {
148
+ children: [/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("p", {
138
149
  className: "text-xs uppercase tracking-wide text-text-secondary",
139
- children: I("vibecontrols.pages.ai.contextLabel", "Active context")
140
- }), /* @__PURE__ */ j("h2", {
150
+ children: P("vibecontrols.pages.ai.contextLabel", "Active context")
151
+ }), /* @__PURE__ */ k("h2", {
141
152
  className: "text-sm font-semibold text-text-primary mt-0.5",
142
- children: I("vibecontrols.pages.ai.configHeading", "AI configuration")
143
- })] }), /* @__PURE__ */ M("div", {
153
+ children: P("vibecontrols.pages.ai.configHeading", "AI configuration")
154
+ })] }), /* @__PURE__ */ A("div", {
144
155
  className: "flex items-center gap-3",
145
- children: [/* @__PURE__ */ j(S, {
156
+ children: [/* @__PURE__ */ k(x, {
146
157
  aiHref: "/ai",
147
158
  activeMode: "ai"
148
- }), /* @__PURE__ */ j(p, {
149
- label: I("vibecontrols.pages.ai.agentSelectorLabel", "Agent"),
159
+ }), /* @__PURE__ */ k(d, {
160
+ label: P("vibecontrols.pages.ai.agentSelectorLabel", "Agent"),
150
161
  compact: !0
151
162
  })]
152
163
  })]
153
- }), /* @__PURE__ */ j("div", {
164
+ }), /* @__PURE__ */ k("div", {
154
165
  className: "flex-1 overflow-auto p-4 sm:p-6 space-y-6",
155
- children: /* @__PURE__ */ M(d, {
156
- agentId: U || null,
157
- children: [/* @__PURE__ */ j(x, { agent: G }), /* @__PURE__ */ j(ie, { agent: G })]
166
+ children: /* @__PURE__ */ A(l, {
167
+ agentId: V || null,
168
+ children: [/* @__PURE__ */ k(b, { agent: U }), /* @__PURE__ */ k(re, { agent: U })]
158
169
  })
159
170
  })]
160
- }) : /* @__PURE__ */ M(N, {
171
+ }) : /* @__PURE__ */ A(j, {
161
172
  className: "flex flex-col h-[calc(100vh-6.5rem)] bg-bg-surface overflow-hidden",
162
173
  children: [
163
- /* @__PURE__ */ M("div", {
174
+ /* @__PURE__ */ A("div", {
164
175
  className: "flex items-center justify-between gap-3 border-b border-border-default px-4 sm:px-6 py-3",
165
- children: [/* @__PURE__ */ M("div", { children: [/* @__PURE__ */ j("p", {
176
+ children: [/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("p", {
166
177
  className: "text-xs uppercase tracking-wide text-text-secondary",
167
- children: I("vibecontrols.pages.ai.contextLabel", "Active context")
168
- }), /* @__PURE__ */ j("h2", {
178
+ children: P("vibecontrols.pages.ai.contextLabel", "Active context")
179
+ }), /* @__PURE__ */ k("h2", {
169
180
  className: "text-sm font-semibold text-text-primary mt-0.5",
170
- children: I("vibecontrols.pages.ai.contextHeading", "AI workbench")
171
- })] }), /* @__PURE__ */ M("div", {
181
+ children: P("vibecontrols.pages.ai.contextHeading", "AI workbench")
182
+ })] }), /* @__PURE__ */ A("div", {
172
183
  className: "flex items-center gap-3",
173
- children: [/* @__PURE__ */ j(S, {
184
+ children: [/* @__PURE__ */ k(x, {
174
185
  aiHref: "/ai",
175
186
  activeMode: "ai"
176
- }), /* @__PURE__ */ j(p, {
177
- label: I("vibecontrols.pages.ai.agentSelectorLabel", "Agent"),
187
+ }), /* @__PURE__ */ k(d, {
188
+ label: P("vibecontrols.pages.ai.agentSelectorLabel", "Agent"),
178
189
  compact: !0
179
190
  })]
180
191
  })]
181
192
  }),
182
- /* @__PURE__ */ j(b, { active: "workbench" }),
183
- /* @__PURE__ */ j("div", {
193
+ /* @__PURE__ */ k(y, { active: "workbench" }),
194
+ /* @__PURE__ */ k("div", {
184
195
  className: "flex-1 min-h-0 overflow-auto p-4 sm:p-6 lg:p-0",
185
- children: /* @__PURE__ */ j(d, {
186
- agentId: U || null,
187
- children: /* @__PURE__ */ j(u, {
188
- agentId: U || null,
189
- onInstalled: () => void le(),
196
+ children: /* @__PURE__ */ k(l, {
197
+ agentId: V || null,
198
+ children: /* @__PURE__ */ k(c, {
199
+ agentId: V || null,
200
+ onInstalled: () => void fe(),
190
201
  requirements: [{
191
- packages: [c],
202
+ packages: [o],
192
203
  mode: "all",
193
- eyebrow: I("vibecontrols.pages.ai.pluginRequiredEyebrow", "AI plugin required"),
194
- title: I("vibecontrols.pages.ai.coreTitle", "Install the AI orchestrator"),
195
- description: I("vibecontrols.pages.ai.coreDescription", "The AI page routes prompts and sessions through the AI orchestrator plugin on your agent. Install it to continue.")
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.")
196
207
  }, {
197
- packages: l,
208
+ packages: s,
198
209
  mode: "any",
199
- eyebrow: I("vibecontrols.pages.ai.providerEyebrow", "AI provider required"),
200
- title: I("vibecontrols.pages.ai.providerTitle", "Install at least one AI provider"),
201
- description: I("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.")
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.")
202
213
  }],
203
- children: /* @__PURE__ */ j(w, {
204
- fallback: /* @__PURE__ */ j("div", {
214
+ children: /* @__PURE__ */ k(oe, {
215
+ fallback: /* @__PURE__ */ k("div", {
205
216
  className: "flex items-center justify-center h-full",
206
- children: /* @__PURE__ */ j(a, { message: "Loading..." })
217
+ children: /* @__PURE__ */ k(i, { message: "Loading..." })
207
218
  }),
208
- children: /* @__PURE__ */ j(ne, {
209
- sidebar: /* @__PURE__ */ j(re, {
210
- agent: G,
211
- onDeleteSession: se,
212
- onDeleteSelected: ce
219
+ children: /* @__PURE__ */ k(_, {
220
+ sidebar: /* @__PURE__ */ k(v, {
221
+ agent: U,
222
+ onDeleteSession: ue,
223
+ onDeleteSelected: de
213
224
  }),
214
- detailPanel: q ? /* @__PURE__ */ j(y, {
215
- sessionId: q,
216
- agent: G
225
+ detailPanel: J ? /* @__PURE__ */ k(ae, {
226
+ sessionId: J,
227
+ agent: U
217
228
  }) : void 0,
218
- children: /* @__PURE__ */ j(v, { agent: G })
229
+ children: /* @__PURE__ */ k(ie, { agent: U })
219
230
  })
220
231
  })
221
232
  })
@@ -225,6 +236,6 @@ function P() {
225
236
  });
226
237
  }
227
238
  //#endregion
228
- export { P as AgentManagerPage };
239
+ export { M as AgentManagerPage };
229
240
 
230
241
  //# 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 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 if (isNative()) void nativeNotify('success');\n } catch {\n if (isNative()) void nativeNotify('error');\n }\n },\n [agentRef]\n );\n\n const handleDeleteSelected = useCallback(\n async (sessionIds: string[]) => {\n if (!agentId) return;\n try {\n await bulkDeleteSessions(agentRef, sessionIds);\n if (isNative()) void nativeNotify('success');\n } catch {\n if (isNative()) void nativeNotify('error');\n }\n },\n [agentRef]\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(\n (cached?.agentPlugins?.installed ?? []).map((p) => p.packageName)\n );\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,SAAgB,IAAmB;CACjC,IAAM,EAAE,KAAK,GAAU,WAAW,MAAmB,GAElD,EACG,IAAK,GAAO,EACZ,IAAiB,GAAiB,EAElC,EAAE,WAAQ,SAAS,GAAe,OAAO,MAAgB,GAAsB,EAC/E,IAAkB,GAAsB,MAAM,EAAE,cAAc,EAI9D,IAAc,QAAc;AAChC,MAAI,GAAiB;GACnB,IAAM,IAAQ,EAAO,MAAM,MAAM,EAAE,OAAO,EAAgB;AAC1D,OAAI,EAAO,QAAO;;AAEpB,SAAO,EAAO,MAAM,MAAM,EAAE,YAAY,EAAE,UAAU,IAAI;IACvD,CAAC,GAAQ,EAAgB,CAAC,EAEvB,IAAU,GAAa,MAAM,IAE7B,EAAE,QAAQ,MAAkB,EAAsB,GAAa,MAAM,KAAK,EAC1E,IAAW,SACR;EAAE,IAAI;EAAS,SAAS;EAAe,GAC9C,CAAC,GAAS,EAAc,CACzB,EACK,IAAc,GAAsB,MAAM,EAAE,YAAY,EACxD,IAAqB,GAAsB,MAAM,EAAE,mBAAmB,EACtE,IAAuB,GAAsB,MAAM,EAAE,qBAAqB,EAK1E,CAAC,KAAgB,IAAiB;AACxC,SAAgB;EACd,IAAM,IAAc,EAAa,IAAI,SAAS;AAC9C,IAAqB;GACnB,cAAc,IAAc,SAAS;GACrC,QAAQ,KAAe;GACxB,CAAC;IACD,CAAC,GAAc,EAAqB,CAAC;CAUxC,IAAM,EAAE,gBAAgB,GAAuB,SAAS,MAAmB,EAHjD,QAAc,CAAC,GAAiB,GAAG,EAAqB,EAAE,EAAE,CAAC,EAKrF,KAAW,KACZ,EAEK,IAAS,IAAiB,EAG1B,IAAuB,EAAO,GAAM;AAG1C,SAAgB;AACd,EAAI,KAAkB,KACpB,EAAY,GAAgB,WAAW,EAAe,MAAM,GAAG,EAAE,GAAG;IAErE;EAAC;EAAgB;EAAS;EAAY,CAAC;CAE1C,IAAM,KAAsB,EAC1B,OAAO,MAAsB;AACtB,QACL,KAAI;AAEF,GADA,MAAM,GAAiB,GAAU,EAAU,EACvC,GAAU,IAAO,EAAa,UAAU;UACtC;AACN,GAAI,GAAU,IAAO,EAAa,QAAQ;;IAG9C,CAAC,EAAS,CACX,EAEK,KAAuB,EAC3B,OAAO,MAAyB;AACzB,QACL,KAAI;AAEF,GADA,MAAM,EAAmB,GAAU,EAAW,EAC1C,GAAU,IAAO,EAAa,UAAU;UACtC;AACN,GAAI,GAAU,IAAO,EAAa,QAAQ;;IAG9C,CAAC,EAAS,CACX,EAWK,KAA0B,EAAY,YAAY;AACtD,MAAI,EAAqB,WAAW,CAAC,EAAS;AAC9C,IAAqB,UAAU;EAI/B,IAAM,UAAwC;AAC5C,OAAI;IACF,IAAM,IAAS,EAAO,UAA6B;KACjD,OAAO;KACP,WAAW,EAAE,YAAS;KACvB,CAAC,EACI,IAAQ,IAAI,KACf,GAAQ,cAAc,aAAa,EAAE,EAAE,KAAK,MAAM,EAAE,YAAY,CAClE;AACD,WAAO,EAAqB,MAAM,MAAQ,EAAM,IAAI,EAAI,CAAC;WACnD;AACN,WAAO;;;AAGX,MAAI;AAIF,OADA,MAAM,GAAgB,EAClB,GAAwB,CAAE;AAI9B,QAAK,IAAI,IAAU,GAAG,IAAU,IAAI,KAAW,GAAG;AAChD,UAAM,IAAI,SAAS,MAAY,WAAW,GAAS,IAAK,CAAC;AACzD,QAAI;KACF,IAAM,EAAE,YAAS,MAAM,EAAO,MAAyB;MACrD,OAAO;MACP,WAAW,EAAE,YAAS;MACtB,aAAa;MACd,CAAC,EACI,IAAgB,GAAM,cAAc,aAAa,EAAE,EACnD,IAAQ,IAAI,IAAI,EAAc,KAAK,MAAM,EAAE,YAAY,CAAC;AAC9D,SAAI,EAAqB,MAAM,MAAQ,EAAM,IAAI,EAAI,CAAC,CAAE;aACjD,GAAK;AAGZ,aAAQ,KAAK,qCAAqC,EAAI;;;AAI1D,SAAM,GAAgB;YACd;AACR,KAAqB,UAAU;;IAEhC;EAAC;EAAS;EAAQ;EAAe,CAAC;AAsFrC,QAnFA,GAAyB,EAOrB,KAAkB,KAAW,IAE7B,kBAAC,GAAD;EAAY,WAAU;YACpB,kBAAC,GAAD,EACE,SAAS,EACP,wCACA,2CACD,EACD,CAAA;EACS,CAAA,GAIb,IAEA,kBAAC,GAAD;EAAY,WAAU;YACpB,kBAAC,IAAD;GAAY,OAAM;GAAwB,SAAS,EAAY;GAAW,CAAA;EAC/D,CAAA,GAIb,EAAO,WAAW,IAElB,kBAAC,GAAD;EAAY,WAAU;YACpB,kBAAC,GAAD;GACE,MAAM,kBAAC,GAAD,EAAgB,WAAU,8BAA+B,CAAA;GAC/D,OAAO,EAAG,gDAAgD,sBAAsB;GAChF,aAAa,EACX,mDACA,6FACD;GACD,QACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAe,UAAU;IACxC,WAAU;cAET,EAAG,oCAAoC,eAAe;IAChD,CAAA;GAEX,CAAA;EACS,CAAA,GAIb,MAAa,WAEb,kBAAC,GAAD;EAAY,WAAU;YAAtB,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;IAAG,WAAU;cACV,EAAG,sCAAsC,iBAAiB;IACzD,CAAA,EACJ,kBAAC,MAAD;IAAI,WAAU;cACX,EAAG,uCAAuC,mBAAmB;IAC3D,CAAA,CACD,EAAA,CAAA,EACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAc,QAAO;KAAM,YAAW;KAAO,CAAA,EAC7C,kBAAC,GAAD;KACE,OAAO,EAAG,4CAA4C,QAAQ;KAC9D,SAAA;KACA,CAAA,CACE;MACF;MAEN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IAAuB,SAAS,KAAW;cAA3C,CACE,kBAAC,GAAD,EAAuB,OAAO,GAAY,CAAA,EAC1C,kBAAC,IAAD,EAAmB,OAAO,GAAY,CAAA,CAChB;;GACpB,CAAA,CACK;MAKf,kBAAC,GAAD;EAAY,WAAU;YAAtB;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;KAAG,WAAU;eACV,EAAG,sCAAsC,iBAAiB;KACzD,CAAA,EACJ,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,wCAAwC,eAAe;KACxD,CAAA,CACD,EAAA,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CAGE,kBAAC,GAAD;MAAc,QAAO;MAAM,YAAW;MAAO,CAAA,EAC7C,kBAAC,GAAD;MAAe,OAAO,EAAG,4CAA4C,QAAQ;MAAE,SAAA;MAAU,CAAA,CACrF;OACF;;GAEN,kBAAC,GAAD,EAAe,QAAO,aAAc,CAAA;GAEpC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KAAuB,SAAS,KAAW;eACzC,kBAAC,GAAD;MACE,SAAS,KAAW;MAQpB,mBAAmB,KAAK,IAAyB;MACjD,cAAc,CACZ;OACE,UAAU,CAAC,EAAgB;OAC3B,MAAM;OACN,SAAS,EAAG,+CAA+C,qBAAqB;OAChF,OAAO,EAAG,mCAAmC,8BAA8B;OAC3E,aAAa,EACX,yCACA,oHACD;OACF,EACD;OACE,UAAU;OACV,MAAM;OACN,SAAS,EAAG,yCAAyC,uBAAuB;OAC5E,OAAO,EACL,uCACA,mCACD;OACD,aAAa,EACX,6CACA,gHACD;OACF,CACF;gBAED,kBAAC,GAAD;OACE,UACE,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,GAAD,EAAc,SAAQ,cAAe,CAAA;QACjC,CAAA;iBAGR,kBAAC,IAAD;QACE,SACE,kBAAC,IAAD;SACE,OAAO;SACP,iBAAiB;SACjB,kBAAkB;SAClB,CAAA;QAEJ,aACE,IACE,kBAAC,GAAD;SAAyB,WAAW;SAAoB,OAAO;SAAY,CAAA,GACzE,KAAA;kBAGN,kBAAC,GAAD,EAAoB,OAAO,GAAY,CAAA;QACpB,CAAA;OACZ,CAAA;MACA,CAAA;KACS,CAAA;IACpB,CAAA;GACK"}
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(\n (cached?.agentPlugins?.installed ?? []).map((p) => p.packageName)\n );\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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"}