@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.
- package/dist/components/agent-manager/dialogs/NewSessionDialog.js +16 -15
- package/dist/components/agent-manager/dialogs/NewSessionDialog.js.map +1 -1
- package/dist/components/docs/DocsTabPanel.js +7 -4
- package/dist/components/docs/DocsTabPanel.js.map +1 -1
- package/dist/pages/VibesPage.js +3 -3
- package/dist/pages/VibesPage.js.map +1 -1
- package/dist/pages/ai/AgentManagerPage.js +138 -127
- package/dist/pages/ai/AgentManagerPage.js.map +1 -1
- package/dist/providers/VibeControlsProvider.js +43 -35
- package/dist/providers/VibeControlsProvider.js.map +1 -1
- package/package.json +1 -1
|
@@ -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
|
|
6
|
-
import { LoadingState as
|
|
7
|
-
import { ErrorState as
|
|
8
|
-
import { EmptyState as
|
|
9
|
-
import { usePluginAvailability as
|
|
10
|
-
import { AI_CORE_PACKAGE as
|
|
11
|
-
import { PluginGate as
|
|
12
|
-
import { RequireAgentReachable as
|
|
13
|
-
import { useActiveAgentProfile as
|
|
14
|
-
import { AgentSelector as
|
|
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
|
|
17
|
-
import { bulkDeleteSessions as
|
|
18
|
-
import { useAgentManagerStore as
|
|
19
|
-
import { AgentManagerLayout as
|
|
20
|
-
import { AgentManagerSidebar as
|
|
21
|
-
import { BridleConfigPanel as
|
|
22
|
-
import { AgentManagerCenter as
|
|
23
|
-
import { AgentManagerDetailPanel as
|
|
24
|
-
import { AiSectionTabs as
|
|
25
|
-
import { ClaudeCredentialsCard as
|
|
26
|
-
import { AIModeToggle as
|
|
27
|
-
import { useAgentManagerKeyboard as
|
|
28
|
-
import { Suspense as
|
|
29
|
-
import { MessagesSquare as
|
|
30
|
-
import { useParams as
|
|
31
|
-
import { useApolloClient as
|
|
32
|
-
import { jsx as
|
|
33
|
-
import { MotionPage as
|
|
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
|
|
36
|
-
let { tab:
|
|
37
|
-
if (
|
|
38
|
-
let e =
|
|
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
|
|
42
|
-
}, [
|
|
43
|
-
id:
|
|
44
|
-
profile:
|
|
45
|
-
}), [
|
|
46
|
-
|
|
47
|
-
let e =
|
|
48
|
-
|
|
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
|
-
}, [
|
|
53
|
-
let { initialLoading:
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
N,
|
|
58
|
+
V,
|
|
59
|
+
W
|
|
60
60
|
]);
|
|
61
|
-
let
|
|
62
|
-
if (
|
|
63
|
-
await
|
|
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
|
-
|
|
65
|
+
f() && p("error");
|
|
66
66
|
}
|
|
67
|
-
}, [
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
76
|
+
f() && p("error");
|
|
72
77
|
}
|
|
73
|
-
}, [
|
|
74
|
-
|
|
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:
|
|
91
|
+
variables: { agentId: V }
|
|
81
92
|
}), n = new Set((t?.agentPlugins?.installed ?? []).map((e) => e.packageName));
|
|
82
|
-
return
|
|
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:
|
|
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 (
|
|
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
|
-
|
|
118
|
+
V,
|
|
108
119
|
Q,
|
|
109
120
|
Z
|
|
110
121
|
]);
|
|
111
|
-
return
|
|
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__ */
|
|
114
|
-
}) :
|
|
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__ */
|
|
127
|
+
children: /* @__PURE__ */ k(a, {
|
|
117
128
|
title: "Failed to load agents",
|
|
118
|
-
message:
|
|
129
|
+
message: R.message
|
|
119
130
|
})
|
|
120
|
-
}) :
|
|
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__ */
|
|
123
|
-
icon: /* @__PURE__ */
|
|
124
|
-
title:
|
|
125
|
-
description:
|
|
126
|
-
action: /* @__PURE__ */
|
|
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: () =>
|
|
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:
|
|
141
|
+
children: P("vibecontrols.pages.ai.goToAgents", "Go to Agents")
|
|
131
142
|
})
|
|
132
143
|
})
|
|
133
|
-
}) :
|
|
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__ */
|
|
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__ */
|
|
148
|
+
children: [/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("p", {
|
|
138
149
|
className: "text-xs uppercase tracking-wide text-text-secondary",
|
|
139
|
-
children:
|
|
140
|
-
}), /* @__PURE__ */
|
|
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:
|
|
143
|
-
})] }), /* @__PURE__ */
|
|
153
|
+
children: P("vibecontrols.pages.ai.configHeading", "AI configuration")
|
|
154
|
+
})] }), /* @__PURE__ */ A("div", {
|
|
144
155
|
className: "flex items-center gap-3",
|
|
145
|
-
children: [/* @__PURE__ */
|
|
156
|
+
children: [/* @__PURE__ */ k(x, {
|
|
146
157
|
aiHref: "/ai",
|
|
147
158
|
activeMode: "ai"
|
|
148
|
-
}), /* @__PURE__ */
|
|
149
|
-
label:
|
|
159
|
+
}), /* @__PURE__ */ k(d, {
|
|
160
|
+
label: P("vibecontrols.pages.ai.agentSelectorLabel", "Agent"),
|
|
150
161
|
compact: !0
|
|
151
162
|
})]
|
|
152
163
|
})]
|
|
153
|
-
}), /* @__PURE__ */
|
|
164
|
+
}), /* @__PURE__ */ k("div", {
|
|
154
165
|
className: "flex-1 overflow-auto p-4 sm:p-6 space-y-6",
|
|
155
|
-
children: /* @__PURE__ */
|
|
156
|
-
agentId:
|
|
157
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
176
|
+
children: [/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("p", {
|
|
166
177
|
className: "text-xs uppercase tracking-wide text-text-secondary",
|
|
167
|
-
children:
|
|
168
|
-
}), /* @__PURE__ */
|
|
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:
|
|
171
|
-
})] }), /* @__PURE__ */
|
|
181
|
+
children: P("vibecontrols.pages.ai.contextHeading", "AI workbench")
|
|
182
|
+
})] }), /* @__PURE__ */ A("div", {
|
|
172
183
|
className: "flex items-center gap-3",
|
|
173
|
-
children: [/* @__PURE__ */
|
|
184
|
+
children: [/* @__PURE__ */ k(x, {
|
|
174
185
|
aiHref: "/ai",
|
|
175
186
|
activeMode: "ai"
|
|
176
|
-
}), /* @__PURE__ */
|
|
177
|
-
label:
|
|
187
|
+
}), /* @__PURE__ */ k(d, {
|
|
188
|
+
label: P("vibecontrols.pages.ai.agentSelectorLabel", "Agent"),
|
|
178
189
|
compact: !0
|
|
179
190
|
})]
|
|
180
191
|
})]
|
|
181
192
|
}),
|
|
182
|
-
/* @__PURE__ */
|
|
183
|
-
/* @__PURE__ */
|
|
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__ */
|
|
186
|
-
agentId:
|
|
187
|
-
children: /* @__PURE__ */
|
|
188
|
-
agentId:
|
|
189
|
-
onInstalled: () => void
|
|
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: [
|
|
202
|
+
packages: [o],
|
|
192
203
|
mode: "all",
|
|
193
|
-
eyebrow:
|
|
194
|
-
title:
|
|
195
|
-
description:
|
|
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:
|
|
208
|
+
packages: s,
|
|
198
209
|
mode: "any",
|
|
199
|
-
eyebrow:
|
|
200
|
-
title:
|
|
201
|
-
description:
|
|
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__ */
|
|
204
|
-
fallback: /* @__PURE__ */
|
|
214
|
+
children: /* @__PURE__ */ k(oe, {
|
|
215
|
+
fallback: /* @__PURE__ */ k("div", {
|
|
205
216
|
className: "flex items-center justify-center h-full",
|
|
206
|
-
children: /* @__PURE__ */
|
|
217
|
+
children: /* @__PURE__ */ k(i, { message: "Loading..." })
|
|
207
218
|
}),
|
|
208
|
-
children: /* @__PURE__ */
|
|
209
|
-
sidebar: /* @__PURE__ */
|
|
210
|
-
agent:
|
|
211
|
-
onDeleteSession:
|
|
212
|
-
onDeleteSelected:
|
|
219
|
+
children: /* @__PURE__ */ k(_, {
|
|
220
|
+
sidebar: /* @__PURE__ */ k(v, {
|
|
221
|
+
agent: U,
|
|
222
|
+
onDeleteSession: ue,
|
|
223
|
+
onDeleteSelected: de
|
|
213
224
|
}),
|
|
214
|
-
detailPanel:
|
|
215
|
-
sessionId:
|
|
216
|
-
agent:
|
|
225
|
+
detailPanel: J ? /* @__PURE__ */ k(ae, {
|
|
226
|
+
sessionId: J,
|
|
227
|
+
agent: U
|
|
217
228
|
}) : void 0,
|
|
218
|
-
children: /* @__PURE__ */
|
|
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 {
|
|
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":"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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 { 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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"}
|