@burdenoff/microfe-vibecontrols 2026.613.1 → 2026.618.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/components/agents/AgentConnectionRecovery.js +100 -94
  2. package/dist/components/agents/AgentConnectionRecovery.js.map +1 -1
  3. package/dist/components/agents/AgentMaintenanceTab.js +177 -160
  4. package/dist/components/agents/AgentMaintenanceTab.js.map +1 -1
  5. package/dist/components/agents/OpenInBrowserEditorButton.js +102 -94
  6. package/dist/components/agents/OpenInBrowserEditorButton.js.map +1 -1
  7. package/dist/components/assistant/AssistantChatArea.js +1 -0
  8. package/dist/components/assistant/AssistantChatArea.js.map +1 -1
  9. package/dist/components/assistant/AssistantModeSelector.js +20 -19
  10. package/dist/components/assistant/AssistantModeSelector.js.map +1 -1
  11. package/dist/components/tunnels/TunnelCard.js +3 -3
  12. package/dist/components/tunnels/TunnelCard.js.map +1 -1
  13. package/dist/components/tunnels/TunnelPublicAccessPanel.js +36 -36
  14. package/dist/components/tunnels/TunnelPublicAccessPanel.js.map +1 -1
  15. package/dist/config/assistantUsecases.js +11 -0
  16. package/dist/config/assistantUsecases.js.map +1 -1
  17. package/dist/constants/permissions.js +38 -6
  18. package/dist/constants/permissions.js.map +1 -1
  19. package/dist/index.js +4 -3
  20. package/dist/pages/CatalogDetailPage.js +155 -155
  21. package/dist/pages/CatalogDetailPage.js.map +1 -1
  22. package/dist/pages/CatalogPage.js +110 -109
  23. package/dist/pages/CatalogPage.js.map +1 -1
  24. package/dist/pages/ComponentDetailPage.js +338 -338
  25. package/dist/pages/ComponentDetailPage.js.map +1 -1
  26. package/dist/pages/ComponentsPage.js +104 -103
  27. package/dist/pages/ComponentsPage.js.map +1 -1
  28. package/dist/pages/TargetDetailsPage.js +140 -132
  29. package/dist/pages/TargetDetailsPage.js.map +1 -1
  30. package/dist/pages/TemplateDetailPage.js +201 -199
  31. package/dist/pages/TemplateDetailPage.js.map +1 -1
  32. package/dist/pages/TemplatesPage.js +62 -61
  33. package/dist/pages/TemplatesPage.js.map +1 -1
  34. package/dist/pages/VibeDetailsPage.js +568 -555
  35. package/dist/pages/VibeDetailsPage.js.map +1 -1
  36. package/dist/pages/ai/AIBookmarksPage.js +104 -89
  37. package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
  38. package/dist/pages/ai/AIPage.js +116 -107
  39. package/dist/pages/ai/AIPage.js.map +1 -1
  40. package/dist/pages/ai/AISessionDetailPage.js +46 -34
  41. package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
  42. package/dist/pages/ai/AgentManagerPage.js +112 -100
  43. package/dist/pages/ai/AgentManagerPage.js.map +1 -1
  44. package/dist/pages/tunnels/TunnelDetailsPage.js +177 -153
  45. package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
  46. package/dist/pages/tunnels/TunnelsTab.js +119 -111
  47. package/dist/pages/tunnels/TunnelsTab.js.map +1 -1
  48. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js +24 -24
  49. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js.map +1 -1
  50. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +9 -8
  51. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
  52. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js +13 -13
  53. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js.map +1 -1
  54. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +19 -15
  55. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js.map +1 -1
  56. package/dist/services/assistantApi.js +9 -3
  57. package/dist/services/assistantApi.js.map +1 -1
  58. package/dist/services/createSandboxAssistantTransport.js +120 -0
  59. package/dist/services/createSandboxAssistantTransport.js.map +1 -0
  60. package/dist/store/assistantStore.js +1 -1
  61. package/dist/store/assistantStore.js.map +1 -1
  62. package/package.json +5 -1
@@ -1,87 +1,90 @@
1
1
  import { useVibeNavigate as e } from "../../providers/VibeControlsProvider.js";
2
2
  import t from "../../hooks/useCachedInitialData.js";
3
3
  import { PageHeader as n } from "../../components/shared/PageHeader.js";
4
- import { ErrorState as r } from "../../components/shared/ErrorState.js";
5
- import { EmptyState as i } from "../../components/shared/EmptyState.js";
6
- import { AI_CORE_PACKAGE as a, AI_PROVIDER_PACKAGES as o } from "../../constants/pluginCatalog.js";
7
- import { PluginGate as s } from "../../components/shared/PluginGate.js";
8
- import { RequireAgentReachable as c } from "../../components/shared/RequireAgentReachable.js";
9
- import { useActiveAgentProfile as l } from "../../hooks/useActiveAgentProfile.js";
4
+ import { ErrorState as ee } from "../../components/shared/ErrorState.js";
5
+ import { EmptyState as r } from "../../components/shared/EmptyState.js";
6
+ import { AI_CORE_PACKAGE as i, AI_PROVIDER_PACKAGES as a } from "../../constants/pluginCatalog.js";
7
+ import { PluginGate as o } from "../../components/shared/PluginGate.js";
8
+ import { RequireAgentReachable as s } from "../../components/shared/RequireAgentReachable.js";
9
+ import { useActiveAgentProfile as c } from "../../hooks/useActiveAgentProfile.js";
10
10
  import "../../components/shared/index.js";
11
+ import { VIBE_PERMISSIONS as l } from "../../constants/permissions.js";
11
12
  import { PageSkeleton as u } from "../../components/shared/PageSkeleton.js";
12
- import { PluginHarnessPicker as d } from "../../components/ai/PluginHarnessPicker.js";
13
- import { AITemplatesTab as f } from "../../components/ai/AITemplatesTab.js";
14
- import { AIContextsTab as p } from "../../components/ai/AIContextsTab.js";
15
- import { AIPromptsTab as m } from "../../components/ai/AIPromptsTab.js";
16
- import { AITasksTab as h } from "../../components/ai/AITasksTab.js";
17
- import { AIStatsTab as ee } from "../../components/ai/AIStatsTab.js";
18
- import { AIPlaygroundTab as g } from "../../components/ai/AIPlaygroundTab.js";
19
- import { BridleConfigPanel as _ } from "../../components/agent-manager/BridleConfigPanel.js";
20
- import { AIOverviewTab as v } from "../../components/ai/AIOverviewTab.js";
21
- import { InstructionFilesManager as y } from "../../components/ai/InstructionFilesManager.js";
22
- import { AISessionsTab as te } from "../../components/ai/AISessionsTab.js";
23
- import { AIQueueTab as b } from "../../components/ai/AIQueueTab.js";
24
- import { ClaudeCredentialsCard as x } from "../../components/ai/ClaudeCredentialsCard.js";
25
- import { AIPlanPanel as S } from "../../components/ai/AIPlanPanel.js";
26
- import { AIModeToggle as C } from "../../components/ai/AIModeToggle.js";
27
- import { useCallback as w, useMemo as T, useState as ne } from "react";
28
- import { useI18n as E } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
29
- import { BarChart3 as D, FileCode2 as O, FileText as k, LayoutDashboard as A, ListChecks as j, ListTodo as M, MessageSquare as N, MessagesSquare as P, Play as F, ScrollText as I } from "lucide-react";
30
- import { useMatch as L, useParams as R } from "react-router-dom";
31
- import { jsx as z, jsxs as B } from "react/jsx-runtime";
32
- import { MotionPage as V } from "@burdenoff/fe-libs/shared/motion";
13
+ import { PluginHarnessPicker as te } from "../../components/ai/PluginHarnessPicker.js";
14
+ import { AITemplatesTab as ne } from "../../components/ai/AITemplatesTab.js";
15
+ import { AIContextsTab as d } from "../../components/ai/AIContextsTab.js";
16
+ import { AIPromptsTab as re } from "../../components/ai/AIPromptsTab.js";
17
+ import { AITasksTab as f } from "../../components/ai/AITasksTab.js";
18
+ import { AIStatsTab as p } from "../../components/ai/AIStatsTab.js";
19
+ import { AIPlaygroundTab as m } from "../../components/ai/AIPlaygroundTab.js";
20
+ import { BridleConfigPanel as ie } from "../../components/agent-manager/BridleConfigPanel.js";
21
+ import { AIOverviewTab as h } from "../../components/ai/AIOverviewTab.js";
22
+ import { InstructionFilesManager as g } from "../../components/ai/InstructionFilesManager.js";
23
+ import { AISessionsTab as ae } from "../../components/ai/AISessionsTab.js";
24
+ import { AIQueueTab as _ } from "../../components/ai/AIQueueTab.js";
25
+ import { ClaudeCredentialsCard as v } from "../../components/ai/ClaudeCredentialsCard.js";
26
+ import { AIPlanPanel as y } from "../../components/ai/AIPlanPanel.js";
27
+ import { AIModeToggle as b } from "../../components/ai/AIModeToggle.js";
28
+ import { useCallback as x, useMemo as S, useState as oe } from "react";
29
+ import { useI18n as se } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
30
+ import { BarChart3 as C, FileCode2 as w, FileText as T, LayoutDashboard as E, ListChecks as D, ListTodo as O, MessageSquare as k, MessagesSquare as A, Play as j, ScrollText as M } from "lucide-react";
31
+ import { useMatch as N, useParams as P } from "react-router-dom";
32
+ import { usePermissions as F } from "@burdenoff/fe-libs/shared/providers/shell";
33
+ import { jsx as I, jsxs as L } from "react/jsx-runtime";
34
+ import { AccessDenied as R } from "@burdenoff/fe-libs/shared/components";
35
+ import { MotionPage as z } from "@burdenoff/fe-libs/shared/motion";
33
36
  //#region src/pages/ai/AIPage.tsx
34
- var H = [
37
+ var B = [
35
38
  {
36
39
  id: "overview",
37
- icon: A
40
+ icon: E
38
41
  },
39
42
  {
40
43
  id: "templates",
41
- icon: O
44
+ icon: w
42
45
  },
43
46
  {
44
47
  id: "contexts",
45
- icon: k
48
+ icon: T
46
49
  },
47
50
  {
48
51
  id: "prompts",
49
- icon: N
52
+ icon: k
50
53
  },
51
54
  {
52
55
  id: "instructions",
53
- icon: I
56
+ icon: M
54
57
  },
55
58
  {
56
59
  id: "sessions",
57
- icon: P
60
+ icon: A
58
61
  },
59
62
  {
60
63
  id: "queue",
61
- icon: j
64
+ icon: D
62
65
  },
63
66
  {
64
67
  id: "tasks",
65
- icon: M
68
+ icon: O
66
69
  },
67
70
  {
68
71
  id: "stats",
69
- icon: D
72
+ icon: C
70
73
  },
71
74
  {
72
75
  id: "playground",
73
- icon: F
76
+ icon: j
74
77
  },
75
78
  {
76
79
  id: "config",
77
- icon: A
80
+ icon: E
78
81
  }
79
- ], U = new Set(H.map((e) => e.id));
80
- function W() {
81
- let { t: D } = E(), { tab: O } = R(), k = L("vibecontrols/ai-tools/plan") ? "plan" : "ai", A = O && U.has(O) ? O : "overview", j = e(), M = w((e, t) => {
82
- let n = D(e);
82
+ ], V = new Set(B.map((e) => e.id));
83
+ function H() {
84
+ let { t: C } = se(), { hasPermission: w, isLoading: T } = F(), E = w(l.AGENT_READ), { tab: D } = P(), O = N("vibecontrols/ai-tools/plan") ? "plan" : "ai", k = D && V.has(D) ? D : "overview", j = e(), M = x((e, t) => {
85
+ let n = C(e);
83
86
  return n === e ? t : n;
84
- }, [D]), N = w((e) => {
87
+ }, [C]), H = x((e) => {
85
88
  switch (e) {
86
89
  case "overview": return M("ai.overview", "Overview");
87
90
  case "templates": return M("ai.templates", "Templates");
@@ -96,127 +99,130 @@ function W() {
96
99
  case "config": return M("ai.config", "Config");
97
100
  default: return e;
98
101
  }
99
- }, [M]), { agents: F, loading: I, error: W, refetch: G } = t();
100
- W && console.error("[ai] failed to load initial workspace data", W);
101
- let K = T(() => F.find((e) => e.isActive && e.tunnelUrl) ?? null, [F]), q = K?.id ?? "", { active: J } = l(K?.id ?? null), Y = T(() => ({
102
- id: q,
103
- profile: J
104
- }), [q, J]), X = w((e) => {
102
+ }, [M]), { agents: U, loading: W, error: G, refetch: K } = t();
103
+ G && console.error("[ai] failed to load initial workspace data", G);
104
+ let q = S(() => U.find((e) => e.isActive && e.tunnelUrl) ?? null, [U]), J = q?.id ?? "", { active: Y } = c(q?.id ?? null), X = S(() => ({
105
+ id: J,
106
+ profile: Y
107
+ }), [J, Y]), ce = x((e) => {
105
108
  j(e === "overview" ? "/ai-tools/ai" : `/ai-tools/ai/${e}`);
106
- }, [j]), Z = w((e) => {
109
+ }, [j]), Z = x((e) => {
107
110
  j(`/ai-tools/sessions/${e}`);
108
- }, [j]), re = !!q, [Q, $] = ne(null), ie = w(() => {
111
+ }, [j]), le = !!J, [Q, $] = oe(null), ue = x(() => {
109
112
  $(M("ai.pluginInstalled", "Plugin installed. Opening AI chat…")), console.info("[ai] orchestrator install completed — navigating to AI chat"), j("/ai");
110
- }, [M, j]), ae = w(() => {
113
+ }, [M, j]), de = x(() => {
111
114
  $(M("ai.harnessUpdated", "Harness updated.")), console.info("[ai] harness picker changed");
112
115
  }, [M]);
113
- return /* @__PURE__ */ B(V, {
116
+ return T ? /* @__PURE__ */ I(z, {
117
+ className: "space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen",
118
+ children: /* @__PURE__ */ I(u, { variant: "detail" })
119
+ }) : E ? /* @__PURE__ */ L(z, {
114
120
  className: "space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen",
115
121
  children: [
116
- /* @__PURE__ */ z(n, {
122
+ /* @__PURE__ */ I(n, {
117
123
  title: M("nav.ai", "AI"),
118
124
  description: M("ai.description", "Manage AI sessions, prompts, templates, and contexts for your vibecoding workflow")
119
125
  }),
120
- /* @__PURE__ */ z("div", {
126
+ /* @__PURE__ */ I("div", {
121
127
  "data-tour": "vibecontrols-ai-mode-toggle",
122
- children: /* @__PURE__ */ z(C, {
123
- aiHref: `/ai-tools/ai/${A}`,
124
- activeMode: k
128
+ children: /* @__PURE__ */ I(b, {
129
+ aiHref: `/ai-tools/ai/${k}`,
130
+ activeMode: O
125
131
  })
126
132
  }),
127
- k === "ai" && /* @__PURE__ */ z("div", {
133
+ O === "ai" && /* @__PURE__ */ I("div", {
128
134
  className: "border-b border-border-default -mx-4 sm:-mx-6 px-4 sm:px-6",
129
135
  "data-tour": "vibecontrols-ai-tabs-nav",
130
- children: /* @__PURE__ */ z("nav", {
136
+ children: /* @__PURE__ */ I("nav", {
131
137
  className: "flex gap-1 overflow-x-auto pb-1",
132
138
  role: "tablist",
133
- children: H.map((e) => {
134
- let t = e.icon, n = A === e.id;
135
- return /* @__PURE__ */ B("button", {
139
+ children: B.map((e) => {
140
+ let t = e.icon, n = k === e.id;
141
+ return /* @__PURE__ */ L("button", {
136
142
  type: "button",
137
143
  role: "tab",
138
144
  "aria-selected": n,
139
- onClick: () => X(e.id),
145
+ onClick: () => ce(e.id),
140
146
  className: `flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-t-md border-b-2 px-2.5 py-2 text-xs font-medium transition-colors sm:px-3 sm:py-2.5 sm:text-sm ${n ? "border-action-primary-bg text-action-primary-bg" : "border-transparent text-text-secondary hover:text-text-primary hover:border-border-default"}`,
141
- children: [/* @__PURE__ */ z(t, { className: "size-3.5 sm:h-4 sm:w-4" }), N(e.id)]
147
+ children: [/* @__PURE__ */ I(t, { className: "size-3.5 sm:h-4 sm:w-4" }), H(e.id)]
142
148
  }, e.id);
143
149
  })
144
150
  })
145
151
  }),
146
- I && F.length === 0 ? /* @__PURE__ */ z(u, {
152
+ W && U.length === 0 ? /* @__PURE__ */ I(u, {
147
153
  variant: "rows",
148
154
  count: 6
149
- }) : W ? /* @__PURE__ */ z(r, {
155
+ }) : G ? /* @__PURE__ */ I(ee, {
150
156
  title: M("ai.loadFailed.title", "Could not load the AI workspace"),
151
157
  message: M("ai.loadFailed.message", "We couldn't load the AI workspace. Please try again in a moment."),
152
- onRetry: G
153
- }) : re ? k === "plan" ? /* @__PURE__ */ z(c, {
154
- agentId: q,
155
- children: /* @__PURE__ */ z(S, {
156
- agent: Y,
157
- tunnelUrl: K?.tunnelUrl ?? null
158
+ onRetry: K
159
+ }) : le ? O === "plan" ? /* @__PURE__ */ I(s, {
160
+ agentId: J,
161
+ children: /* @__PURE__ */ I(y, {
162
+ agent: X,
163
+ tunnelUrl: q?.tunnelUrl ?? null
158
164
  })
159
- }) : /* @__PURE__ */ z(c, {
160
- agentId: q,
161
- children: /* @__PURE__ */ z("div", {
165
+ }) : /* @__PURE__ */ I(s, {
166
+ agentId: J,
167
+ children: /* @__PURE__ */ I("div", {
162
168
  "data-tour": "vibecontrols-ai-plugin-gate",
163
- children: /* @__PURE__ */ z(s, {
164
- agentId: q,
165
- required: [a],
169
+ children: /* @__PURE__ */ I(o, {
170
+ agentId: J,
171
+ required: [i],
166
172
  mode: "all",
167
173
  eyebrow: M("ai.pluginRequired", "AI plugin required"),
168
174
  title: M("ai.installOrchestrator", "Install the AI orchestrator"),
169
175
  description: M("ai.installOrchestratorDesc", "The AI page routes prompts and sessions through the AI orchestrator plugin on your agent. Install it to continue."),
170
- onInstalled: ie,
171
- children: /* @__PURE__ */ B("div", {
176
+ onInstalled: ue,
177
+ children: /* @__PURE__ */ L("div", {
172
178
  className: "space-y-6",
173
179
  children: [
174
- Q && /* @__PURE__ */ z("div", {
180
+ Q && /* @__PURE__ */ I("div", {
175
181
  role: "status",
176
182
  className: "rounded-md border border-status-success-border bg-status-success-bg px-3 py-2 text-xs text-status-success-text",
177
183
  children: Q
178
184
  }),
179
- /* @__PURE__ */ z(d, {
180
- agentId: q,
181
- packages: o,
185
+ /* @__PURE__ */ I(te, {
186
+ agentId: J,
187
+ packages: a,
182
188
  title: M("ai.harnessesTitle", "AI harnesses"),
183
189
  description: M("ai.harnessesDesc", "Install and manage the coding-agent harnesses available on this agent. You can install multiple and switch between them per-session."),
184
- onChange: ae
190
+ onChange: de
185
191
  }),
186
- /* @__PURE__ */ B("div", { children: [
187
- A === "overview" && /* @__PURE__ */ z(v, {
188
- agent: Y,
192
+ /* @__PURE__ */ L("div", { children: [
193
+ k === "overview" && /* @__PURE__ */ I(h, {
194
+ agent: X,
189
195
  onNavigateToSession: Z
190
196
  }),
191
- A === "templates" && /* @__PURE__ */ z(f, { agentId: q }),
192
- A === "contexts" && /* @__PURE__ */ z(p, { agent: Y }),
193
- A === "prompts" && /* @__PURE__ */ z(m, { agent: Y }),
194
- A === "instructions" && /* @__PURE__ */ z(y, { agentId: q }),
195
- A === "sessions" && /* @__PURE__ */ z(te, {
196
- agent: Y,
197
+ k === "templates" && /* @__PURE__ */ I(ne, { agentId: J }),
198
+ k === "contexts" && /* @__PURE__ */ I(d, { agent: X }),
199
+ k === "prompts" && /* @__PURE__ */ I(re, { agent: X }),
200
+ k === "instructions" && /* @__PURE__ */ I(g, { agentId: J }),
201
+ k === "sessions" && /* @__PURE__ */ I(ae, {
202
+ agent: X,
197
203
  onNavigateToSession: Z
198
204
  }),
199
- A === "queue" && /* @__PURE__ */ z(b, {
200
- agent: Y,
205
+ k === "queue" && /* @__PURE__ */ I(_, {
206
+ agent: X,
201
207
  onNavigateToSession: Z
202
208
  }),
203
- A === "tasks" && /* @__PURE__ */ z(h, {}),
204
- A === "stats" && /* @__PURE__ */ z(ee, { agent: Y }),
205
- A === "playground" && /* @__PURE__ */ z(g, { agent: Y }),
206
- A === "config" && /* @__PURE__ */ B("div", {
209
+ k === "tasks" && /* @__PURE__ */ I(f, {}),
210
+ k === "stats" && /* @__PURE__ */ I(p, { agent: X }),
211
+ k === "playground" && /* @__PURE__ */ I(m, { agent: X }),
212
+ k === "config" && /* @__PURE__ */ L("div", {
207
213
  className: "space-y-6",
208
- children: [/* @__PURE__ */ z(x, { agent: Y }), /* @__PURE__ */ z(_, { agent: Y })]
214
+ children: [/* @__PURE__ */ I(v, { agent: X }), /* @__PURE__ */ I(ie, { agent: X })]
209
215
  })
210
216
  ] })
211
217
  ]
212
218
  })
213
219
  })
214
220
  })
215
- }) : /* @__PURE__ */ z(i, {
216
- icon: /* @__PURE__ */ z(P, { className: "size-8 text-text-secondary" }),
221
+ }) : /* @__PURE__ */ I(r, {
222
+ icon: /* @__PURE__ */ I(A, { className: "size-8 text-text-secondary" }),
217
223
  title: M("ai.noActiveAgent", "No active agent available"),
218
224
  description: M("ai.noActiveAgentDescription", "AI features require an active agent with a configured tunnel URL and API key. Add an agent or start an existing one."),
219
- action: /* @__PURE__ */ z("button", {
225
+ action: /* @__PURE__ */ I("button", {
220
226
  type: "button",
221
227
  onClick: () => j("/agents"),
222
228
  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",
@@ -224,9 +230,12 @@ function W() {
224
230
  })
225
231
  })
226
232
  ]
233
+ }) : /* @__PURE__ */ I(R, {
234
+ title: M("ai.denied.title", "Access Denied"),
235
+ description: M("ai.denied.description", "You do not have permission to view AI features.")
227
236
  });
228
237
  }
229
238
  //#endregion
230
- export { W as AIPage };
239
+ export { H as AIPage };
231
240
 
232
241
  //# sourceMappingURL=AIPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AIPage.js","names":[],"sources":["../../../src/pages/ai/AIPage.tsx"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport { useMatch, useParams } from 'react-router-dom';\nimport {\n LayoutDashboard,\n FileCode2,\n FileText,\n MessageSquare,\n MessagesSquare,\n ListTodo,\n ListChecks,\n BarChart3,\n Play,\n ScrollText,\n} from 'lucide-react';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport {\n PageHeader,\n EmptyState,\n ErrorState,\n PluginGate,\n RequireAgentReachable,\n} from '@/components/shared';\nimport { PageSkeleton } from '@/components/shared/PageSkeleton';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { AI_CORE_PACKAGE, AI_PROVIDER_PACKAGES } from '@/constants/pluginCatalog';\nimport { PluginHarnessPicker } from '@/components/ai/PluginHarnessPicker';\n\nimport { AIOverviewTab } from '@/components/ai/AIOverviewTab';\nimport { AITemplatesTab } from '@/components/ai/AITemplatesTab';\nimport { AIContextsTab } from '@/components/ai/AIContextsTab';\nimport { AIPromptsTab } from '@/components/ai/AIPromptsTab';\nimport { InstructionFilesManager } from '@/components/ai/InstructionFilesManager';\nimport { AISessionsTab } from '@/components/ai/AISessionsTab';\nimport { AITasksTab } from '@/components/ai/AITasksTab';\nimport { AIQueueTab } from '@/components/ai/AIQueueTab';\nimport { AIStatsTab } from '@/components/ai/AIStatsTab';\nimport { AIPlaygroundTab } from '@/components/ai/AIPlaygroundTab';\nimport { ClaudeCredentialsCard } from '@/components/ai/ClaudeCredentialsCard';\nimport { BridleConfigPanel } from '@/components/agent-manager/BridleConfigPanel';\nimport { AIPlanPanel } from '@/components/ai/AIPlanPanel';\nimport { AIModeToggle } from '@/components/ai/AIModeToggle';\n\ntype AIMode = 'plan' | 'ai';\n\ntype AITab =\n | 'overview'\n | 'templates'\n | 'contexts'\n | 'prompts'\n | 'instructions'\n | 'sessions'\n | 'queue'\n | 'tasks'\n | 'stats'\n | 'playground'\n | 'config';\n\nconst tabs: { id: AITab; icon: typeof LayoutDashboard }[] = [\n { id: 'overview', icon: LayoutDashboard },\n { id: 'templates', icon: FileCode2 },\n { id: 'contexts', icon: FileText },\n { id: 'prompts', icon: MessageSquare },\n { id: 'instructions', icon: ScrollText },\n { id: 'sessions', icon: MessagesSquare },\n { id: 'queue', icon: ListChecks },\n { id: 'tasks', icon: ListTodo },\n { id: 'stats', icon: BarChart3 },\n { id: 'playground', icon: Play },\n { id: 'config', icon: LayoutDashboard },\n];\n\nconst validTabs = new Set<string>(tabs.map((t) => t.id));\n\n/**\n * AI page — tab-based layout for AI / vibecoding features.\n *\n * URL shape:\n * /ai-tools → routed to /ai-tools/ai/overview (handled in VibeControlsRoutes).\n * /ai-tools/plan → Plan mode (full-bleed plannotator iframe panel).\n * /ai-tools/ai/:tab → AI mode (the existing 9 sub-tabs).\n *\n * The mode toggle below `PageHeader` switches between the two without a\n * full route reload — the AIPlanPanel inside Plan mode reuses the same\n * agent context that AI mode already loaded.\n */\nexport function AIPage() {\n const { t } = useI18n();\n const { tab: tabParam } = useParams<{ tab?: string }>();\n const planRouteMatch = useMatch('vibecontrols/ai-tools/plan');\n const activeMode: AIMode = planRouteMatch ? 'plan' : 'ai';\n const activeTab: AITab = tabParam && validTabs.has(tabParam) ? (tabParam as AITab) : 'overview';\n const handleNavigate = useVibeNavigate();\n\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const tabLabel = useCallback(\n (tabId: AITab): string => {\n switch (tabId) {\n case 'overview':\n return tr('ai.overview', 'Overview');\n case 'templates':\n return tr('ai.templates', 'Templates');\n case 'contexts':\n return tr('ai.contexts', 'Contexts');\n case 'prompts':\n return tr('ai.prompts', 'Prompts');\n case 'instructions':\n return tr('ai.instructions', 'Instructions');\n case 'sessions':\n return tr('nav.sessions', 'Sessions');\n case 'queue':\n return tr('ai.queue', 'Queue');\n case 'tasks':\n return tr('ai.tasks', 'Tasks');\n case 'stats':\n return tr('ai.stats', 'Stats');\n case 'playground':\n return tr('ai.playground', 'Playground');\n case 'config':\n return tr('ai.config', 'Config');\n default:\n return tabId;\n }\n },\n [tr]\n );\n\n const { agents, loading: agentsLoading, error: agentsError, refetch } = useCachedInitialData();\n\n // If the initial data query throws (e.g. gateway query-cost limit, network\n // error, transient federation issue), surface a friendly fallback rather\n // than the raw GraphQL error. The technical details still go to the console\n // for debuggability — without PII, since the error message itself never\n // contains secrets.\n if (agentsError) {\n console.error('[ai] failed to load initial workspace data', agentsError);\n }\n const activeAgent = useMemo(\n () => agents.find((agent) => agent.isActive && agent.tunnelUrl) ?? null,\n [agents]\n );\n const agentId = activeAgent?.id ?? '';\n // AgentRef threads the canonical agent → profile → plugins/data\n // hierarchy through every aiApi call. Components receive the ref\n // and construct paths via `agentApiPath(profile, ...)`.\n const { active: activeProfile } = useActiveAgentProfile(activeAgent?.id ?? null);\n const agentRef = useMemo(\n () => ({ id: agentId, profile: activeProfile }),\n [agentId, activeProfile]\n );\n\n const switchTab = useCallback(\n (tab: AITab) => {\n handleNavigate(tab === 'overview' ? '/ai-tools/ai' : `/ai-tools/ai/${tab}`);\n },\n [handleNavigate]\n );\n\n const navigateToSession = useCallback(\n (sessionId: string) => {\n handleNavigate(`/ai-tools/sessions/${sessionId}`);\n },\n [handleNavigate]\n );\n\n const hasAgent = !!agentId;\n\n // Surface install lifecycle for debuggability. PluginGate / PluginHarnessPicker\n // already render inline error chips, but a console breadcrumb + a top-level\n // banner helps when the install actually succeeds on the agent but a stale\n // detection cache hides the success — without this the install button looked\n // like it silently swallowed errors.\n const [lastInstallNote, setLastInstallNote] = useState<string | null>(null);\n // PluginGate fires this only on the unsatisfied → satisfied transition (once\n // the orchestrator is actually live on the agent). When that happens, route\n // straight into the AI chat (AgentManagerPage at `/ai`) instead of leaving\n // the user on a \"Refreshing…\" note that needed a manual reload (G5). No\n // window.location.reload() — the SPA navigation re-renders the workbench with\n // the freshly-detected plugin state.\n const handleInstalled = useCallback(() => {\n setLastInstallNote(tr('ai.pluginInstalled', 'Plugin installed. Opening AI chat…'));\n console.info('[ai] orchestrator install completed — navigating to AI chat');\n handleNavigate('/ai');\n }, [tr, handleNavigate]);\n const handleHarnessChange = useCallback(() => {\n setLastInstallNote(tr('ai.harnessUpdated', 'Harness updated.'));\n\n console.info('[ai] harness picker changed');\n }, [tr]);\n\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <PageHeader\n title={tr('nav.ai', 'AI')}\n description={tr(\n 'ai.description',\n 'Manage AI sessions, prompts, templates, and contexts for your vibecoding workflow'\n )}\n />\n\n {/* Mode pivot — Plan / AI. Sits below PageHeader, above the\n AI-mode sub-tab strip. Switching to Plan hides the 9 sub-tabs\n and renders the AIPlanPanel in their place. Stays inside\n /ai-tools so the active sub-tab survives the toggle. */}\n {/* AIModeToggle is a custom component that doesn't forward rest props\n onto a DOM node, so the tour anchor lives on a wrapper <div>. */}\n <div data-tour=\"vibecontrols-ai-mode-toggle\">\n <AIModeToggle aiHref={`/ai-tools/ai/${activeTab}`} activeMode={activeMode} />\n </div>\n\n {/* AI sub-tab navigation — only rendered in AI mode. */}\n {activeMode === 'ai' && (\n <div\n className=\"border-b border-border-default -mx-4 sm:-mx-6 px-4 sm:px-6\"\n data-tour=\"vibecontrols-ai-tabs-nav\"\n >\n <nav className=\"flex gap-1 overflow-x-auto pb-1\" role=\"tablist\">\n {tabs.map((tab) => {\n const Icon = tab.icon;\n const isActive = activeTab === tab.id;\n return (\n <button\n type=\"button\"\n key={tab.id}\n role=\"tab\"\n aria-selected={isActive}\n onClick={() => switchTab(tab.id)}\n className={`flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-t-md border-b-2 px-2.5 py-2 text-xs font-medium transition-colors sm:px-3 sm:py-2.5 sm:text-sm ${\n isActive\n ? 'border-action-primary-bg text-action-primary-bg'\n : 'border-transparent text-text-secondary hover:text-text-primary hover:border-border-default'\n }`}\n >\n <Icon className=\"size-3.5 sm:h-4 sm:w-4\" />\n {tabLabel(tab.id)}\n </button>\n );\n })}\n </nav>\n </div>\n )}\n\n {/* Content */}\n {agentsLoading && agents.length === 0 ? (\n <PageSkeleton variant=\"rows\" count={6} />\n ) : agentsError ? (\n <ErrorState\n title={tr('ai.loadFailed.title', 'Could not load the AI workspace')}\n message={tr(\n 'ai.loadFailed.message',\n \"We couldn't load the AI workspace. Please try again in a moment.\"\n )}\n onRetry={refetch}\n />\n ) : !hasAgent ? (\n <EmptyState\n icon={<MessagesSquare className=\"size-8 text-text-secondary\" />}\n title={tr('ai.noActiveAgent', 'No active agent available')}\n description={tr(\n 'ai.noActiveAgentDescription',\n 'AI features require an active agent with a configured tunnel URL and API key. Add an agent 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('ai.goToAgents', 'Go to Agents')}\n </button>\n }\n />\n ) : activeMode === 'plan' ? (\n <RequireAgentReachable agentId={agentId}>\n <AIPlanPanel agent={agentRef} tunnelUrl={activeAgent?.tunnelUrl ?? null} />\n </RequireAgentReachable>\n ) : (\n <RequireAgentReachable agentId={agentId}>\n {/* PluginGate is a custom component that doesn't forward rest props\n onto a DOM node, so the tour anchor lives on a wrapper <div>. */}\n <div data-tour=\"vibecontrols-ai-plugin-gate\">\n <PluginGate\n agentId={agentId}\n required={[AI_CORE_PACKAGE]}\n mode=\"all\"\n eyebrow={tr('ai.pluginRequired', 'AI plugin required')}\n title={tr('ai.installOrchestrator', 'Install the AI orchestrator')}\n description={tr(\n 'ai.installOrchestratorDesc',\n 'The AI page routes prompts and sessions through the AI orchestrator plugin on your agent. Install it to continue.'\n )}\n onInstalled={handleInstalled}\n >\n <div className=\"space-y-6\">\n {lastInstallNote && (\n <div\n role=\"status\"\n className=\"rounded-md border border-status-success-border bg-status-success-bg px-3 py-2 text-xs text-status-success-text\"\n >\n {lastInstallNote}\n </div>\n )}\n <PluginHarnessPicker\n agentId={agentId}\n packages={AI_PROVIDER_PACKAGES}\n title={tr('ai.harnessesTitle', 'AI harnesses')}\n description={tr(\n 'ai.harnessesDesc',\n 'Install and manage the coding-agent harnesses available on this agent. You can install multiple and switch between them per-session.'\n )}\n onChange={handleHarnessChange}\n />\n <div>\n {activeTab === 'overview' && (\n <AIOverviewTab agent={agentRef} onNavigateToSession={navigateToSession} />\n )}\n {activeTab === 'templates' && <AITemplatesTab agentId={agentId} />}\n {activeTab === 'contexts' && <AIContextsTab agent={agentRef} />}\n {activeTab === 'prompts' && <AIPromptsTab agent={agentRef} />}\n {activeTab === 'instructions' && <InstructionFilesManager agentId={agentId} />}\n {activeTab === 'sessions' && (\n <AISessionsTab agent={agentRef} onNavigateToSession={navigateToSession} />\n )}\n {activeTab === 'queue' && (\n <AIQueueTab agent={agentRef} onNavigateToSession={navigateToSession} />\n )}\n {activeTab === 'tasks' && <AITasksTab />}\n {activeTab === 'stats' && <AIStatsTab agent={agentRef} />}\n {activeTab === 'playground' && <AIPlaygroundTab agent={agentRef} />}\n {activeTab === 'config' && (\n <div className=\"space-y-6\">\n <ClaudeCredentialsCard agent={agentRef} />\n <BridleConfigPanel agent={agentRef} />\n </div>\n )}\n </div>\n </div>\n </PluginGate>\n </div>\n </RequireAgentReachable>\n )}\n </MotionPage>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AIPage.js","names":[],"sources":["../../../src/pages/ai/AIPage.tsx"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport { useMatch, useParams } from 'react-router-dom';\nimport {\n LayoutDashboard,\n FileCode2,\n FileText,\n MessageSquare,\n MessagesSquare,\n ListTodo,\n ListChecks,\n BarChart3,\n Play,\n ScrollText,\n} from 'lucide-react';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport {\n PageHeader,\n EmptyState,\n ErrorState,\n PluginGate,\n RequireAgentReachable,\n} from '@/components/shared';\nimport { PageSkeleton } from '@/components/shared/PageSkeleton';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { AccessDenied } from '@burdenoff/fe-libs/shared/components';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { AI_CORE_PACKAGE, AI_PROVIDER_PACKAGES } from '@/constants/pluginCatalog';\nimport { PluginHarnessPicker } from '@/components/ai/PluginHarnessPicker';\n\nimport { AIOverviewTab } from '@/components/ai/AIOverviewTab';\nimport { AITemplatesTab } from '@/components/ai/AITemplatesTab';\nimport { AIContextsTab } from '@/components/ai/AIContextsTab';\nimport { AIPromptsTab } from '@/components/ai/AIPromptsTab';\nimport { InstructionFilesManager } from '@/components/ai/InstructionFilesManager';\nimport { AISessionsTab } from '@/components/ai/AISessionsTab';\nimport { AITasksTab } from '@/components/ai/AITasksTab';\nimport { AIQueueTab } from '@/components/ai/AIQueueTab';\nimport { AIStatsTab } from '@/components/ai/AIStatsTab';\nimport { AIPlaygroundTab } from '@/components/ai/AIPlaygroundTab';\nimport { ClaudeCredentialsCard } from '@/components/ai/ClaudeCredentialsCard';\nimport { BridleConfigPanel } from '@/components/agent-manager/BridleConfigPanel';\nimport { AIPlanPanel } from '@/components/ai/AIPlanPanel';\nimport { AIModeToggle } from '@/components/ai/AIModeToggle';\n\ntype AIMode = 'plan' | 'ai';\n\ntype AITab =\n | 'overview'\n | 'templates'\n | 'contexts'\n | 'prompts'\n | 'instructions'\n | 'sessions'\n | 'queue'\n | 'tasks'\n | 'stats'\n | 'playground'\n | 'config';\n\nconst tabs: { id: AITab; icon: typeof LayoutDashboard }[] = [\n { id: 'overview', icon: LayoutDashboard },\n { id: 'templates', icon: FileCode2 },\n { id: 'contexts', icon: FileText },\n { id: 'prompts', icon: MessageSquare },\n { id: 'instructions', icon: ScrollText },\n { id: 'sessions', icon: MessagesSquare },\n { id: 'queue', icon: ListChecks },\n { id: 'tasks', icon: ListTodo },\n { id: 'stats', icon: BarChart3 },\n { id: 'playground', icon: Play },\n { id: 'config', icon: LayoutDashboard },\n];\n\nconst validTabs = new Set<string>(tabs.map((t) => t.id));\n\n/**\n * AI page — tab-based layout for AI / vibecoding features.\n *\n * URL shape:\n * /ai-tools → routed to /ai-tools/ai/overview (handled in VibeControlsRoutes).\n * /ai-tools/plan → Plan mode (full-bleed plannotator iframe panel).\n * /ai-tools/ai/:tab → AI mode (the existing 9 sub-tabs).\n *\n * The mode toggle below `PageHeader` switches between the two without a\n * full route reload — the AIPlanPanel inside Plan mode reuses the same\n * agent context that AI mode already loaded.\n */\nexport function AIPage() {\n const { t } = useI18n();\n // The AI surface is agent-centric — gate it on `agent:read`, consistent\n // with AgentsLandingPage (defense-in-depth; the gateway enforces it too).\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const canReadAgents = hasPermission(VIBE_PERMISSIONS.AGENT_READ);\n const { tab: tabParam } = useParams<{ tab?: string }>();\n const planRouteMatch = useMatch('vibecontrols/ai-tools/plan');\n const activeMode: AIMode = planRouteMatch ? 'plan' : 'ai';\n const activeTab: AITab = tabParam && validTabs.has(tabParam) ? (tabParam as AITab) : 'overview';\n const handleNavigate = useVibeNavigate();\n\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const tabLabel = useCallback(\n (tabId: AITab): string => {\n switch (tabId) {\n case 'overview':\n return tr('ai.overview', 'Overview');\n case 'templates':\n return tr('ai.templates', 'Templates');\n case 'contexts':\n return tr('ai.contexts', 'Contexts');\n case 'prompts':\n return tr('ai.prompts', 'Prompts');\n case 'instructions':\n return tr('ai.instructions', 'Instructions');\n case 'sessions':\n return tr('nav.sessions', 'Sessions');\n case 'queue':\n return tr('ai.queue', 'Queue');\n case 'tasks':\n return tr('ai.tasks', 'Tasks');\n case 'stats':\n return tr('ai.stats', 'Stats');\n case 'playground':\n return tr('ai.playground', 'Playground');\n case 'config':\n return tr('ai.config', 'Config');\n default:\n return tabId;\n }\n },\n [tr]\n );\n\n const { agents, loading: agentsLoading, error: agentsError, refetch } = useCachedInitialData();\n\n // If the initial data query throws (e.g. gateway query-cost limit, network\n // error, transient federation issue), surface a friendly fallback rather\n // than the raw GraphQL error. The technical details still go to the console\n // for debuggability — without PII, since the error message itself never\n // contains secrets.\n if (agentsError) {\n console.error('[ai] failed to load initial workspace data', agentsError);\n }\n const activeAgent = useMemo(\n () => agents.find((agent) => agent.isActive && agent.tunnelUrl) ?? null,\n [agents]\n );\n const agentId = activeAgent?.id ?? '';\n // AgentRef threads the canonical agent → profile → plugins/data\n // hierarchy through every aiApi call. Components receive the ref\n // and construct paths via `agentApiPath(profile, ...)`.\n const { active: activeProfile } = useActiveAgentProfile(activeAgent?.id ?? null);\n const agentRef = useMemo(\n () => ({ id: agentId, profile: activeProfile }),\n [agentId, activeProfile]\n );\n\n const switchTab = useCallback(\n (tab: AITab) => {\n handleNavigate(tab === 'overview' ? '/ai-tools/ai' : `/ai-tools/ai/${tab}`);\n },\n [handleNavigate]\n );\n\n const navigateToSession = useCallback(\n (sessionId: string) => {\n handleNavigate(`/ai-tools/sessions/${sessionId}`);\n },\n [handleNavigate]\n );\n\n const hasAgent = !!agentId;\n\n // Surface install lifecycle for debuggability. PluginGate / PluginHarnessPicker\n // already render inline error chips, but a console breadcrumb + a top-level\n // banner helps when the install actually succeeds on the agent but a stale\n // detection cache hides the success — without this the install button looked\n // like it silently swallowed errors.\n const [lastInstallNote, setLastInstallNote] = useState<string | null>(null);\n // PluginGate fires this only on the unsatisfied → satisfied transition (once\n // the orchestrator is actually live on the agent). When that happens, route\n // straight into the AI chat (AgentManagerPage at `/ai`) instead of leaving\n // the user on a \"Refreshing…\" note that needed a manual reload (G5). No\n // window.location.reload() — the SPA navigation re-renders the workbench with\n // the freshly-detected plugin state.\n const handleInstalled = useCallback(() => {\n setLastInstallNote(tr('ai.pluginInstalled', 'Plugin installed. Opening AI chat…'));\n console.info('[ai] orchestrator install completed — navigating to AI chat');\n handleNavigate('/ai');\n }, [tr, handleNavigate]);\n const handleHarnessChange = useCallback(() => {\n setLastInstallNote(tr('ai.harnessUpdated', 'Harness updated.'));\n\n console.info('[ai] harness picker changed');\n }, [tr]);\n\n if (permissionsLoading) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <PageSkeleton variant=\"detail\" />\n </MotionPage>\n );\n }\n\n if (!canReadAgents) {\n return (\n <AccessDenied\n title={tr('ai.denied.title', 'Access Denied')}\n description={tr('ai.denied.description', 'You do not have permission to view AI features.')}\n />\n );\n }\n\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <PageHeader\n title={tr('nav.ai', 'AI')}\n description={tr(\n 'ai.description',\n 'Manage AI sessions, prompts, templates, and contexts for your vibecoding workflow'\n )}\n />\n\n {/* Mode pivot — Plan / AI. Sits below PageHeader, above the\n AI-mode sub-tab strip. Switching to Plan hides the 9 sub-tabs\n and renders the AIPlanPanel in their place. Stays inside\n /ai-tools so the active sub-tab survives the toggle. */}\n {/* AIModeToggle is a custom component that doesn't forward rest props\n onto a DOM node, so the tour anchor lives on a wrapper <div>. */}\n <div data-tour=\"vibecontrols-ai-mode-toggle\">\n <AIModeToggle aiHref={`/ai-tools/ai/${activeTab}`} activeMode={activeMode} />\n </div>\n\n {/* AI sub-tab navigation — only rendered in AI mode. */}\n {activeMode === 'ai' && (\n <div\n className=\"border-b border-border-default -mx-4 sm:-mx-6 px-4 sm:px-6\"\n data-tour=\"vibecontrols-ai-tabs-nav\"\n >\n <nav className=\"flex gap-1 overflow-x-auto pb-1\" role=\"tablist\">\n {tabs.map((tab) => {\n const Icon = tab.icon;\n const isActive = activeTab === tab.id;\n return (\n <button\n type=\"button\"\n key={tab.id}\n role=\"tab\"\n aria-selected={isActive}\n onClick={() => switchTab(tab.id)}\n className={`flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-t-md border-b-2 px-2.5 py-2 text-xs font-medium transition-colors sm:px-3 sm:py-2.5 sm:text-sm ${\n isActive\n ? 'border-action-primary-bg text-action-primary-bg'\n : 'border-transparent text-text-secondary hover:text-text-primary hover:border-border-default'\n }`}\n >\n <Icon className=\"size-3.5 sm:h-4 sm:w-4\" />\n {tabLabel(tab.id)}\n </button>\n );\n })}\n </nav>\n </div>\n )}\n\n {/* Content */}\n {agentsLoading && agents.length === 0 ? (\n <PageSkeleton variant=\"rows\" count={6} />\n ) : agentsError ? (\n <ErrorState\n title={tr('ai.loadFailed.title', 'Could not load the AI workspace')}\n message={tr(\n 'ai.loadFailed.message',\n \"We couldn't load the AI workspace. Please try again in a moment.\"\n )}\n onRetry={refetch}\n />\n ) : !hasAgent ? (\n <EmptyState\n icon={<MessagesSquare className=\"size-8 text-text-secondary\" />}\n title={tr('ai.noActiveAgent', 'No active agent available')}\n description={tr(\n 'ai.noActiveAgentDescription',\n 'AI features require an active agent with a configured tunnel URL and API key. Add an agent 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('ai.goToAgents', 'Go to Agents')}\n </button>\n }\n />\n ) : activeMode === 'plan' ? (\n <RequireAgentReachable agentId={agentId}>\n <AIPlanPanel agent={agentRef} tunnelUrl={activeAgent?.tunnelUrl ?? null} />\n </RequireAgentReachable>\n ) : (\n <RequireAgentReachable agentId={agentId}>\n {/* PluginGate is a custom component that doesn't forward rest props\n onto a DOM node, so the tour anchor lives on a wrapper <div>. */}\n <div data-tour=\"vibecontrols-ai-plugin-gate\">\n <PluginGate\n agentId={agentId}\n required={[AI_CORE_PACKAGE]}\n mode=\"all\"\n eyebrow={tr('ai.pluginRequired', 'AI plugin required')}\n title={tr('ai.installOrchestrator', 'Install the AI orchestrator')}\n description={tr(\n 'ai.installOrchestratorDesc',\n 'The AI page routes prompts and sessions through the AI orchestrator plugin on your agent. Install it to continue.'\n )}\n onInstalled={handleInstalled}\n >\n <div className=\"space-y-6\">\n {lastInstallNote && (\n <div\n role=\"status\"\n className=\"rounded-md border border-status-success-border bg-status-success-bg px-3 py-2 text-xs text-status-success-text\"\n >\n {lastInstallNote}\n </div>\n )}\n <PluginHarnessPicker\n agentId={agentId}\n packages={AI_PROVIDER_PACKAGES}\n title={tr('ai.harnessesTitle', 'AI harnesses')}\n description={tr(\n 'ai.harnessesDesc',\n 'Install and manage the coding-agent harnesses available on this agent. You can install multiple and switch between them per-session.'\n )}\n onChange={handleHarnessChange}\n />\n <div>\n {activeTab === 'overview' && (\n <AIOverviewTab agent={agentRef} onNavigateToSession={navigateToSession} />\n )}\n {activeTab === 'templates' && <AITemplatesTab agentId={agentId} />}\n {activeTab === 'contexts' && <AIContextsTab agent={agentRef} />}\n {activeTab === 'prompts' && <AIPromptsTab agent={agentRef} />}\n {activeTab === 'instructions' && <InstructionFilesManager agentId={agentId} />}\n {activeTab === 'sessions' && (\n <AISessionsTab agent={agentRef} onNavigateToSession={navigateToSession} />\n )}\n {activeTab === 'queue' && (\n <AIQueueTab agent={agentRef} onNavigateToSession={navigateToSession} />\n )}\n {activeTab === 'tasks' && <AITasksTab />}\n {activeTab === 'stats' && <AIStatsTab agent={agentRef} />}\n {activeTab === 'playground' && <AIPlaygroundTab agent={agentRef} />}\n {activeTab === 'config' && (\n <div className=\"space-y-6\">\n <ClaudeCredentialsCard agent={agentRef} />\n <BridleConfigPanel agent={agentRef} />\n </div>\n )}\n </div>\n </div>\n </PluginGate>\n </div>\n </RequireAgentReachable>\n )}\n </MotionPage>\n );\n}\n"],"mappings":"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"}