@burdenoff/microfe-vibecontrols 2026.525.4 → 2026.525.6

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.
@@ -1,26 +1,27 @@
1
1
  import { useTr as e } from "../../shared/hooks/useTr.js";
2
- import { SelectionCheckbox as t } from "../shared/SelectionCheckbox.js";
2
+ import { useVibeNavigate as t } from "../../providers/VibeControlsProvider.js";
3
+ import { SelectionCheckbox as n } from "../shared/SelectionCheckbox.js";
3
4
  import "../shared/index.js";
4
- import { updateSessionConfig as n } from "../../services/aiApi.js";
5
- import { useAgentManagerStore as r } from "../../store/agentManagerStore.js";
6
- import { relativeTime as i } from "../../utils/relativeTime.js";
7
- import { useState as a } from "react";
8
- import { Pin as o, Tag as s, Trash2 as c } from "lucide-react";
9
- import { motion as l } from "framer-motion";
10
- import { jsx as u, jsxs as d } from "react/jsx-runtime";
5
+ import { updateSessionConfig as r } from "../../services/aiApi.js";
6
+ import { useAgentManagerStore as i } from "../../store/agentManagerStore.js";
7
+ import { relativeTime as a } from "../../utils/relativeTime.js";
8
+ import { useState as o } from "react";
9
+ import { Pin as s, Tag as c, Trash2 as l } from "lucide-react";
10
+ import { motion as u } from "framer-motion";
11
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
11
12
  //#region src/components/agent-manager/AgentManagerSessionItem.tsx
12
- var f = {
13
+ var p = {
13
14
  active: "bg-status-success-bg",
14
15
  idle: "bg-status-warning-bg",
15
16
  error: "bg-status-error-bg",
16
17
  terminated: "bg-border-default",
17
18
  processing: "bg-status-info-bg"
18
19
  };
19
- function p({ session: p, agent: m, isActive: h, isSelected: g, onDelete: _ }) {
20
- let [v, y] = a(!1), b = e(), x = r((e) => e.openSession), S = r((e) => e.hydrateSessionConfig), C = r((e) => e.pinTab), w = r((e) => e.toggleSessionSelection), T = r((e) => e.tabs).find((e) => e.sessionId === p.id)?.pinned ?? !1, E = f[p.status] ?? "bg-border-default", D = p.config?.tags || [], O = () => {
21
- S(p.id, p), x(p.id, p.name);
20
+ function m({ session: m, agent: h, isActive: g, isSelected: _, onDelete: v }) {
21
+ let [y, b] = o(!1), x = e(), S = t(), C = i((e) => e.openSession), w = i((e) => e.hydrateSessionConfig), T = i((e) => e.pinTab), E = i((e) => e.toggleSessionSelection), D = i((e) => e.tabs).find((e) => e.sessionId === m.id)?.pinned ?? !1, O = p[m.status] ?? "bg-border-default", k = m.config?.tags || [], A = () => {
22
+ w(m.id, m), C(m.id, m.name), S(`/ai/sessions/${m.id}`);
22
23
  };
23
- return /* @__PURE__ */ d(l.div, {
24
+ return /* @__PURE__ */ f(u.div, {
24
25
  layout: !0,
25
26
  initial: {
26
27
  opacity: 0,
@@ -35,100 +36,100 @@ function p({ session: p, agent: m, isActive: h, isSelected: g, onDelete: _ }) {
35
36
  y: -4
36
37
  },
37
38
  transition: { duration: .15 },
38
- onMouseEnter: () => y(!0),
39
- onMouseLeave: () => y(!1),
40
- onClick: O,
41
- className: `group flex items-center gap-2 px-3 py-2 cursor-pointer transition-colors ${h ? "bg-bg-elevated border-l-2 border-action-primary-bg" : "hover:bg-bg-sunken border-l-2 border-transparent"}`,
39
+ onMouseEnter: () => b(!0),
40
+ onMouseLeave: () => b(!1),
41
+ onClick: A,
42
+ className: `group flex items-center gap-2 px-3 py-2 cursor-pointer transition-colors ${g ? "bg-bg-elevated border-l-2 border-action-primary-bg" : "hover:bg-bg-sunken border-l-2 border-transparent"}`,
42
43
  role: "button",
43
44
  tabIndex: 0,
44
45
  onKeyDown: (e) => {
45
- (e.key === "Enter" || e.key === " ") && O();
46
+ (e.key === "Enter" || e.key === " ") && A();
46
47
  },
47
48
  children: [
48
- /* @__PURE__ */ u("div", {
49
- className: `flex-shrink-0 transition-opacity ${v || g ? "opacity-100" : "opacity-0"}`,
49
+ /* @__PURE__ */ d("div", {
50
+ className: `flex-shrink-0 transition-opacity ${y || _ ? "opacity-100" : "opacity-0"}`,
50
51
  onClick: (e) => {
51
- e.stopPropagation(), w(p.id);
52
+ e.stopPropagation(), E(m.id);
52
53
  },
53
- children: /* @__PURE__ */ u(t, {
54
- checked: g,
55
- onChange: () => w(p.id),
56
- ariaLabel: `Select session ${p.name}`
54
+ children: /* @__PURE__ */ d(n, {
55
+ checked: _,
56
+ onChange: () => E(m.id),
57
+ ariaLabel: `Select session ${m.name}`
57
58
  })
58
59
  }),
59
- /* @__PURE__ */ u("span", {
60
- className: `flex-shrink-0 w-2 h-2 rounded-full ${E}`,
61
- title: p.status
60
+ /* @__PURE__ */ d("span", {
61
+ className: `flex-shrink-0 w-2 h-2 rounded-full ${O}`,
62
+ title: m.status
62
63
  }),
63
- /* @__PURE__ */ d("div", {
64
+ /* @__PURE__ */ f("div", {
64
65
  className: "flex-1 min-w-0",
65
66
  children: [
66
- /* @__PURE__ */ d("div", {
67
+ /* @__PURE__ */ f("div", {
67
68
  className: "flex items-center gap-1.5",
68
- children: [/* @__PURE__ */ u("span", {
69
+ children: [/* @__PURE__ */ d("span", {
69
70
  className: "text-sm text-text-primary truncate font-medium",
70
- children: p.name
71
- }), T && /* @__PURE__ */ u(o, { className: "w-3 h-3 text-text-secondary flex-shrink-0" })]
71
+ children: m.name
72
+ }), D && /* @__PURE__ */ d(s, { className: "w-3 h-3 text-text-secondary flex-shrink-0" })]
72
73
  }),
73
- /* @__PURE__ */ d("div", {
74
+ /* @__PURE__ */ f("div", {
74
75
  className: "flex items-center gap-1.5 mt-0.5",
75
76
  children: [
76
- /* @__PURE__ */ u("span", {
77
+ /* @__PURE__ */ d("span", {
77
78
  className: "text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-secondary font-mono",
78
- children: p.agentType
79
+ children: m.agentType
79
80
  }),
80
- typeof p.config?.mode == "string" && /* @__PURE__ */ u("span", {
81
+ typeof m.config?.mode == "string" && /* @__PURE__ */ d("span", {
81
82
  className: "text-[10px] px-1 py-0.5 rounded bg-bg-elevated text-text-muted uppercase font-mono",
82
- children: p.config.mode
83
+ children: m.config.mode
83
84
  }),
84
- p.createdAt && /* @__PURE__ */ u("span", {
85
+ m.createdAt && /* @__PURE__ */ d("span", {
85
86
  className: "text-xs text-text-tertiary truncate",
86
- children: i(p.createdAt)
87
+ children: a(m.createdAt)
87
88
  })
88
89
  ]
89
90
  }),
90
- D.length > 0 && /* @__PURE__ */ d("div", {
91
+ k.length > 0 && /* @__PURE__ */ f("div", {
91
92
  className: "flex gap-0.5 mt-0.5 flex-wrap",
92
- children: [D.slice(0, 3).map((e) => /* @__PURE__ */ u("span", {
93
+ children: [k.slice(0, 3).map((e) => /* @__PURE__ */ d("span", {
93
94
  className: "px-1 py-0.5 text-[10px] bg-bg-elevated text-text-tertiary rounded",
94
95
  children: e
95
- }, e)), D.length > 3 && /* @__PURE__ */ d("span", {
96
+ }, e)), k.length > 3 && /* @__PURE__ */ f("span", {
96
97
  className: "text-[10px] text-text-muted",
97
- children: ["+", D.length - 3]
98
+ children: ["+", k.length - 3]
98
99
  })]
99
100
  })
100
101
  ]
101
102
  }),
102
- v && /* @__PURE__ */ d("div", {
103
+ y && /* @__PURE__ */ f("div", {
103
104
  className: "flex items-center gap-0.5 flex-shrink-0",
104
105
  children: [
105
- /* @__PURE__ */ u("button", {
106
+ /* @__PURE__ */ d("button", {
106
107
  onClick: (e) => {
107
- e.stopPropagation(), S(p.id, p), x(p.id, p.name), C(p.id);
108
+ e.stopPropagation(), w(m.id, m), C(m.id, m.name), T(m.id);
108
109
  },
109
- className: `p-1 rounded transition-colors ${T ? "text-action-primary-bg hover:bg-bg-elevated" : "text-text-secondary hover:text-text-primary hover:bg-bg-elevated"}`,
110
- title: T ? b("vibecontrols.agentManager.sessionItem.unpin", "Unpin") : b("vibecontrols.agentManager.sessionItem.pin", "Pin"),
111
- children: /* @__PURE__ */ u(o, { className: "w-3.5 h-3.5" })
110
+ className: `p-1 rounded transition-colors ${D ? "text-action-primary-bg hover:bg-bg-elevated" : "text-text-secondary hover:text-text-primary hover:bg-bg-elevated"}`,
111
+ title: D ? x("vibecontrols.agentManager.sessionItem.unpin", "Unpin") : x("vibecontrols.agentManager.sessionItem.pin", "Pin"),
112
+ children: /* @__PURE__ */ d(s, { className: "w-3.5 h-3.5" })
112
113
  }),
113
- /* @__PURE__ */ u("button", {
114
+ /* @__PURE__ */ d("button", {
114
115
  onClick: (e) => {
115
116
  e.stopPropagation();
116
- let t = D.join(", "), r = window.prompt("Enter tags (comma-separated):", t);
117
- if (r === null) return;
118
- let i = r.split(",").map((e) => e.trim()).filter(Boolean);
119
- n(m, p.id, { tags: i });
117
+ let t = k.join(", "), n = window.prompt("Enter tags (comma-separated):", t);
118
+ if (n === null) return;
119
+ let i = n.split(",").map((e) => e.trim()).filter(Boolean);
120
+ r(h, m.id, { tags: i });
120
121
  },
121
122
  className: "p-1 rounded text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors",
122
- title: b("vibecontrols.agentManager.sessionItem.editTags", "Edit tags"),
123
- children: /* @__PURE__ */ u(s, { className: "w-3.5 h-3.5" })
123
+ title: x("vibecontrols.agentManager.sessionItem.editTags", "Edit tags"),
124
+ children: /* @__PURE__ */ d(c, { className: "w-3.5 h-3.5" })
124
125
  }),
125
- /* @__PURE__ */ u("button", {
126
+ /* @__PURE__ */ d("button", {
126
127
  onClick: (e) => {
127
- e.stopPropagation(), _(p.id);
128
+ e.stopPropagation(), v(m.id);
128
129
  },
129
130
  className: "p-1 rounded text-text-secondary hover:text-status-error-text hover:bg-bg-elevated transition-colors",
130
- title: b("vibecontrols.agentManager.sessionItem.deleteSession", "Delete session"),
131
- children: /* @__PURE__ */ u(c, { className: "w-3.5 h-3.5" })
131
+ title: x("vibecontrols.agentManager.sessionItem.deleteSession", "Delete session"),
132
+ children: /* @__PURE__ */ d(l, { className: "w-3.5 h-3.5" })
132
133
  })
133
134
  ]
134
135
  })
@@ -136,6 +137,6 @@ function p({ session: p, agent: m, isActive: h, isSelected: g, onDelete: _ }) {
136
137
  });
137
138
  }
138
139
  //#endregion
139
- export { p as AgentManagerSessionItem };
140
+ export { m as AgentManagerSessionItem };
140
141
 
141
142
  //# sourceMappingURL=AgentManagerSessionItem.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AgentManagerSessionItem.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerSessionItem.tsx"],"sourcesContent":["/**\n * Single session row in the sidebar session list.\n *\n * Displays status dot, name, SDK badge, model badge, and relative timestamp.\n * Click opens the session as a tab; hover reveals pin/delete actions.\n */\n\nimport { useState } from 'react';\nimport { Pin, Trash2, Tag } from 'lucide-react';\nimport { motion } from 'framer-motion';\nimport type { AISession, AgentRef } from '@/services/aiApi';\nimport { updateSessionConfig } from '@/services/aiApi';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { SelectionCheckbox } from '@/components/shared';\nimport { relativeTime } from '@/utils/relativeTime';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentManagerSessionItemProps {\n session: AISession;\n agent: AgentRef;\n isActive: boolean;\n isSelected: boolean;\n onDelete: (sessionId: string) => void;\n}\n\nconst STATUS_DOT_COLORS: Record<string, string> = {\n active: 'bg-status-success-bg',\n idle: 'bg-status-warning-bg',\n error: 'bg-status-error-bg',\n terminated: 'bg-border-default',\n processing: 'bg-status-info-bg',\n};\n\nexport function AgentManagerSessionItem({\n session,\n agent,\n isActive,\n isSelected,\n onDelete,\n}: AgentManagerSessionItemProps) {\n const [hovered, setHovered] = useState(false);\n const tr = useTr();\n const openSession = useAgentManagerStore((s) => s.openSession);\n const hydrateSessionConfig = useAgentManagerStore((s) => s.hydrateSessionConfig);\n const pinTab = useAgentManagerStore((s) => s.pinTab);\n const toggleSessionSelection = useAgentManagerStore((s) => s.toggleSessionSelection);\n const tabs = useAgentManagerStore((s) => s.tabs);\n\n const isPinned = tabs.find((t) => t.sessionId === session.id)?.pinned ?? false;\n const dotColor = STATUS_DOT_COLORS[session.status] ?? 'bg-border-default';\n const tags: string[] = ((session.config as Record<string, unknown>)?.tags as string[]) || [];\n\n const handleClick = () => {\n hydrateSessionConfig(session.id, session);\n openSession(session.id, session.name);\n };\n\n const handlePin = (e: React.MouseEvent) => {\n e.stopPropagation();\n hydrateSessionConfig(session.id, session);\n openSession(session.id, session.name);\n pinTab(session.id);\n };\n\n const handleDelete = (e: React.MouseEvent) => {\n e.stopPropagation();\n onDelete(session.id);\n };\n\n const handleEditTags = (e: React.MouseEvent) => {\n e.stopPropagation();\n const currentTags = tags.join(', ');\n const input = window.prompt('Enter tags (comma-separated):', currentTags);\n if (input === null) return;\n const newTags = input\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n void updateSessionConfig(agent, session.id, { tags: newTags });\n };\n\n const handleCheckbox = (e: React.MouseEvent) => {\n e.stopPropagation();\n toggleSessionSelection(session.id);\n };\n\n return (\n <motion.div\n layout\n initial={{ opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -4 }}\n transition={{ duration: 0.15 }}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n onClick={handleClick}\n className={`group flex items-center gap-2 px-3 py-2 cursor-pointer transition-colors ${\n isActive\n ? 'bg-bg-elevated border-l-2 border-action-primary-bg'\n : 'hover:bg-bg-sunken border-l-2 border-transparent'\n }`}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') handleClick();\n }}\n >\n {/* Selection checkbox (on hover or when selected) */}\n <div\n className={`flex-shrink-0 transition-opacity ${hovered || isSelected ? 'opacity-100' : 'opacity-0'}`}\n onClick={handleCheckbox}\n >\n <SelectionCheckbox\n checked={isSelected}\n onChange={() => toggleSessionSelection(session.id)}\n ariaLabel={`Select session ${session.name}`}\n />\n </div>\n\n {/* Status dot */}\n <span className={`flex-shrink-0 w-2 h-2 rounded-full ${dotColor}`} title={session.status} />\n\n {/* Session info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-sm text-text-primary truncate font-medium\">{session.name}</span>\n {isPinned && <Pin className=\"w-3 h-3 text-text-secondary flex-shrink-0\" />}\n </div>\n <div className=\"flex items-center gap-1.5 mt-0.5\">\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-secondary font-mono\">\n {session.agentType}\n </span>\n {typeof (session.config as Record<string, unknown>)?.mode === 'string' && (\n <span className=\"text-[10px] px-1 py-0.5 rounded bg-bg-elevated text-text-muted uppercase font-mono\">\n {(session.config as Record<string, string>).mode}\n </span>\n )}\n {session.createdAt && (\n <span className=\"text-xs text-text-tertiary truncate\">\n {relativeTime(session.createdAt)}\n </span>\n )}\n </div>\n {tags.length > 0 && (\n <div className=\"flex gap-0.5 mt-0.5 flex-wrap\">\n {tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n className=\"px-1 py-0.5 text-[10px] bg-bg-elevated text-text-tertiary rounded\"\n >\n {tag}\n </span>\n ))}\n {tags.length > 3 && (\n <span className=\"text-[10px] text-text-muted\">+{tags.length - 3}</span>\n )}\n </div>\n )}\n </div>\n\n {/* Hover actions */}\n {hovered && (\n <div className=\"flex items-center gap-0.5 flex-shrink-0\">\n <button\n onClick={handlePin}\n className={`p-1 rounded transition-colors ${\n isPinned\n ? 'text-action-primary-bg hover:bg-bg-elevated'\n : 'text-text-secondary hover:text-text-primary hover:bg-bg-elevated'\n }`}\n title={\n isPinned\n ? tr('vibecontrols.agentManager.sessionItem.unpin', 'Unpin')\n : tr('vibecontrols.agentManager.sessionItem.pin', 'Pin')\n }\n >\n <Pin className=\"w-3.5 h-3.5\" />\n </button>\n <button\n onClick={handleEditTags}\n className=\"p-1 rounded text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors\"\n title={tr('vibecontrols.agentManager.sessionItem.editTags', 'Edit tags')}\n >\n <Tag className=\"w-3.5 h-3.5\" />\n </button>\n <button\n onClick={handleDelete}\n className=\"p-1 rounded text-text-secondary hover:text-status-error-text hover:bg-bg-elevated transition-colors\"\n title={tr('vibecontrols.agentManager.sessionItem.deleteSession', 'Delete session')}\n >\n <Trash2 className=\"w-3.5 h-3.5\" />\n </button>\n </div>\n )}\n </motion.div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentManagerSessionItem.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerSessionItem.tsx"],"sourcesContent":["/**\n * Single session row in the sidebar session list.\n *\n * Displays status dot, name, SDK badge, model badge, and relative timestamp.\n * Click opens the session as a tab; hover reveals pin/delete actions.\n */\n\nimport { useState } from 'react';\nimport { Pin, Trash2, Tag } from 'lucide-react';\nimport { motion } from 'framer-motion';\nimport type { AISession, AgentRef } from '@/services/aiApi';\nimport { updateSessionConfig } from '@/services/aiApi';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { SelectionCheckbox } from '@/components/shared';\nimport { relativeTime } from '@/utils/relativeTime';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { useVibeNavigate } from '../../providers/VibeControlsProvider';\n\ninterface AgentManagerSessionItemProps {\n session: AISession;\n agent: AgentRef;\n isActive: boolean;\n isSelected: boolean;\n onDelete: (sessionId: string) => void;\n}\n\nconst STATUS_DOT_COLORS: Record<string, string> = {\n active: 'bg-status-success-bg',\n idle: 'bg-status-warning-bg',\n error: 'bg-status-error-bg',\n terminated: 'bg-border-default',\n processing: 'bg-status-info-bg',\n};\n\nexport function AgentManagerSessionItem({\n session,\n agent,\n isActive,\n isSelected,\n onDelete,\n}: AgentManagerSessionItemProps) {\n const [hovered, setHovered] = useState(false);\n const tr = useTr();\n const navigate = useVibeNavigate();\n const openSession = useAgentManagerStore((s) => s.openSession);\n const hydrateSessionConfig = useAgentManagerStore((s) => s.hydrateSessionConfig);\n const pinTab = useAgentManagerStore((s) => s.pinTab);\n const toggleSessionSelection = useAgentManagerStore((s) => s.toggleSessionSelection);\n const tabs = useAgentManagerStore((s) => s.tabs);\n\n const isPinned = tabs.find((t) => t.sessionId === session.id)?.pinned ?? false;\n const dotColor = STATUS_DOT_COLORS[session.status] ?? 'bg-border-default';\n const tags: string[] = ((session.config as Record<string, unknown>)?.tags as string[]) || [];\n\n const handleClick = () => {\n hydrateSessionConfig(session.id, session);\n openSession(session.id, session.name);\n // Reflect the opened session in the URL so it's deep-linkable / shareable\n // and back-button friendly. useVibeNavigate prepends the mount basePath, so\n // the path stays correct under any host mount or standalone `/`.\n // AgentManagerPage's sessionIdParam effect makes this idempotent\n // (openSession no-ops if the tab is already open).\n navigate(`/ai/sessions/${session.id}`);\n };\n\n const handlePin = (e: React.MouseEvent) => {\n e.stopPropagation();\n hydrateSessionConfig(session.id, session);\n openSession(session.id, session.name);\n pinTab(session.id);\n };\n\n const handleDelete = (e: React.MouseEvent) => {\n e.stopPropagation();\n onDelete(session.id);\n };\n\n const handleEditTags = (e: React.MouseEvent) => {\n e.stopPropagation();\n const currentTags = tags.join(', ');\n const input = window.prompt('Enter tags (comma-separated):', currentTags);\n if (input === null) return;\n const newTags = input\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n void updateSessionConfig(agent, session.id, { tags: newTags });\n };\n\n const handleCheckbox = (e: React.MouseEvent) => {\n e.stopPropagation();\n toggleSessionSelection(session.id);\n };\n\n return (\n <motion.div\n layout\n initial={{ opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -4 }}\n transition={{ duration: 0.15 }}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n onClick={handleClick}\n className={`group flex items-center gap-2 px-3 py-2 cursor-pointer transition-colors ${\n isActive\n ? 'bg-bg-elevated border-l-2 border-action-primary-bg'\n : 'hover:bg-bg-sunken border-l-2 border-transparent'\n }`}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') handleClick();\n }}\n >\n {/* Selection checkbox (on hover or when selected) */}\n <div\n className={`flex-shrink-0 transition-opacity ${hovered || isSelected ? 'opacity-100' : 'opacity-0'}`}\n onClick={handleCheckbox}\n >\n <SelectionCheckbox\n checked={isSelected}\n onChange={() => toggleSessionSelection(session.id)}\n ariaLabel={`Select session ${session.name}`}\n />\n </div>\n\n {/* Status dot */}\n <span className={`flex-shrink-0 w-2 h-2 rounded-full ${dotColor}`} title={session.status} />\n\n {/* Session info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-sm text-text-primary truncate font-medium\">{session.name}</span>\n {isPinned && <Pin className=\"w-3 h-3 text-text-secondary flex-shrink-0\" />}\n </div>\n <div className=\"flex items-center gap-1.5 mt-0.5\">\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-secondary font-mono\">\n {session.agentType}\n </span>\n {typeof (session.config as Record<string, unknown>)?.mode === 'string' && (\n <span className=\"text-[10px] px-1 py-0.5 rounded bg-bg-elevated text-text-muted uppercase font-mono\">\n {(session.config as Record<string, string>).mode}\n </span>\n )}\n {session.createdAt && (\n <span className=\"text-xs text-text-tertiary truncate\">\n {relativeTime(session.createdAt)}\n </span>\n )}\n </div>\n {tags.length > 0 && (\n <div className=\"flex gap-0.5 mt-0.5 flex-wrap\">\n {tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n className=\"px-1 py-0.5 text-[10px] bg-bg-elevated text-text-tertiary rounded\"\n >\n {tag}\n </span>\n ))}\n {tags.length > 3 && (\n <span className=\"text-[10px] text-text-muted\">+{tags.length - 3}</span>\n )}\n </div>\n )}\n </div>\n\n {/* Hover actions */}\n {hovered && (\n <div className=\"flex items-center gap-0.5 flex-shrink-0\">\n <button\n onClick={handlePin}\n className={`p-1 rounded transition-colors ${\n isPinned\n ? 'text-action-primary-bg hover:bg-bg-elevated'\n : 'text-text-secondary hover:text-text-primary hover:bg-bg-elevated'\n }`}\n title={\n isPinned\n ? tr('vibecontrols.agentManager.sessionItem.unpin', 'Unpin')\n : tr('vibecontrols.agentManager.sessionItem.pin', 'Pin')\n }\n >\n <Pin className=\"w-3.5 h-3.5\" />\n </button>\n <button\n onClick={handleEditTags}\n className=\"p-1 rounded text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors\"\n title={tr('vibecontrols.agentManager.sessionItem.editTags', 'Edit tags')}\n >\n <Tag className=\"w-3.5 h-3.5\" />\n </button>\n <button\n onClick={handleDelete}\n className=\"p-1 rounded text-text-secondary hover:text-status-error-text hover:bg-bg-elevated transition-colors\"\n title={tr('vibecontrols.agentManager.sessionItem.deleteSession', 'Delete session')}\n >\n <Trash2 className=\"w-3.5 h-3.5\" />\n </button>\n </div>\n )}\n </motion.div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { useTr as e } from "../../shared/hooks/useTr.js";
2
+ import { useVibeNavigate as t } from "../../providers/VibeControlsProvider.js";
3
+ import { jsx as n } from "react/jsx-runtime";
4
+ import { Tabs as r } from "@burdenoff/fe-libs/chrome";
5
+ //#region src/components/ai/AiSectionTabs.tsx
6
+ function i({ active: i }) {
7
+ let a = t(), o = e();
8
+ return /* @__PURE__ */ n("div", {
9
+ className: "border-b border-border-subtle px-4 sm:px-6 pt-2",
10
+ children: /* @__PURE__ */ n(r, {
11
+ items: [{
12
+ id: "workbench",
13
+ label: o("vibecontrols.pages.ai.tabWorkbench", "Workbench")
14
+ }, {
15
+ id: "bookmarks",
16
+ label: o("vibecontrols.pages.ai.tabBookmarks", "Bookmarks")
17
+ }],
18
+ activeTabId: i,
19
+ onTabChange: (e) => {
20
+ e !== i && a(e === "bookmarks" ? "/ai/bookmarks" : "/ai");
21
+ },
22
+ variant: "underline"
23
+ })
24
+ });
25
+ }
26
+ //#endregion
27
+ export { i as AiSectionTabs };
28
+
29
+ //# sourceMappingURL=AiSectionTabs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiSectionTabs.js","names":[],"sources":["../../../src/components/ai/AiSectionTabs.tsx"],"sourcesContent":["/**\n * Tab strip for the AI section — switches between the workbench (`/ai`) and\n * saved bookmarks (`/ai/bookmarks`). Mirrors the Agents landing tab pattern\n * (fe-libs Tabs, underline variant). The active tab is supplied by the host\n * page since the two tabs map to two routes rather than to swapped content on\n * one page. Navigation goes through useVibeNavigate so paths are basePath-aware\n * (correct under any host mount or standalone `/`).\n */\nimport { Tabs, type TabItem } from '@burdenoff/fe-libs/chrome';\nimport { useVibeNavigate } from '../../providers/VibeControlsProvider';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AiSectionTabsProps {\n active: 'workbench' | 'bookmarks';\n}\n\nexport function AiSectionTabs({ active }: AiSectionTabsProps) {\n const navigate = useVibeNavigate();\n const tr = useTr();\n\n const tabs: TabItem[] = [\n { id: 'workbench', label: tr('vibecontrols.pages.ai.tabWorkbench', 'Workbench') },\n { id: 'bookmarks', label: tr('vibecontrols.pages.ai.tabBookmarks', 'Bookmarks') },\n ];\n\n const handleTabChange = (id: string) => {\n if (id === active) return;\n navigate(id === 'bookmarks' ? '/ai/bookmarks' : '/ai');\n };\n\n return (\n <div className=\"border-b border-border-subtle px-4 sm:px-6 pt-2\">\n <Tabs items={tabs} activeTabId={active} onTabChange={handleTabChange} variant=\"underline\" />\n </div>\n );\n}\n"],"mappings":";;;;;AAgBA,SAAgB,EAAc,EAAE,aAA8B;CAC5D,IAAM,IAAW,GAAiB,EAC5B,IAAK,GAAO;AAYlB,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAM,OAZc,CACtB;IAAE,IAAI;IAAa,OAAO,EAAG,sCAAsC,YAAY;IAAE,EACjF;IAAE,IAAI;IAAa,OAAO,EAAG,sCAAsC,YAAY;IAAE,CAClF;GASsB,aAAa;GAAQ,cAPnB,MAAe;AAClC,UAAO,KACX,EAAS,MAAO,cAAc,kBAAkB,MAAM;;GAKkB,SAAQ;GAAc,CAAA;EACxF,CAAA"}