@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.
- package/dist/components/agent-manager/AgentManagerSessionItem.js +63 -62
- package/dist/components/agent-manager/AgentManagerSessionItem.js.map +1 -1
- package/dist/components/ai/AiSectionTabs.js +29 -0
- package/dist/components/ai/AiSectionTabs.js.map +1 -0
- package/dist/pages/VibeDetailsPage.js +485 -481
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/ai/AIBookmarksPage.js +160 -155
- package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
- package/dist/pages/ai/AgentManagerPage.js +115 -110
- package/dist/pages/ai/AgentManagerPage.js.map +1 -1
- package/dist/services/iframeToken.js +14 -2
- package/dist/services/iframeToken.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
-
import {
|
|
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
|
|
5
|
-
import { useAgentManagerStore as
|
|
6
|
-
import { relativeTime as
|
|
7
|
-
import { useState as
|
|
8
|
-
import { Pin as
|
|
9
|
-
import { motion as
|
|
10
|
-
import { jsx as
|
|
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
|
|
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
|
|
20
|
-
let [
|
|
21
|
-
|
|
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__ */
|
|
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: () =>
|
|
39
|
-
onMouseLeave: () =>
|
|
40
|
-
onClick:
|
|
41
|
-
className: `group flex items-center gap-2 px-3 py-2 cursor-pointer transition-colors ${
|
|
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 === " ") &&
|
|
46
|
+
(e.key === "Enter" || e.key === " ") && A();
|
|
46
47
|
},
|
|
47
48
|
children: [
|
|
48
|
-
/* @__PURE__ */
|
|
49
|
-
className: `flex-shrink-0 transition-opacity ${
|
|
49
|
+
/* @__PURE__ */ d("div", {
|
|
50
|
+
className: `flex-shrink-0 transition-opacity ${y || _ ? "opacity-100" : "opacity-0"}`,
|
|
50
51
|
onClick: (e) => {
|
|
51
|
-
e.stopPropagation(),
|
|
52
|
+
e.stopPropagation(), E(m.id);
|
|
52
53
|
},
|
|
53
|
-
children: /* @__PURE__ */
|
|
54
|
-
checked:
|
|
55
|
-
onChange: () =>
|
|
56
|
-
ariaLabel: `Select session ${
|
|
54
|
+
children: /* @__PURE__ */ d(n, {
|
|
55
|
+
checked: _,
|
|
56
|
+
onChange: () => E(m.id),
|
|
57
|
+
ariaLabel: `Select session ${m.name}`
|
|
57
58
|
})
|
|
58
59
|
}),
|
|
59
|
-
/* @__PURE__ */
|
|
60
|
-
className: `flex-shrink-0 w-2 h-2 rounded-full ${
|
|
61
|
-
title:
|
|
60
|
+
/* @__PURE__ */ d("span", {
|
|
61
|
+
className: `flex-shrink-0 w-2 h-2 rounded-full ${O}`,
|
|
62
|
+
title: m.status
|
|
62
63
|
}),
|
|
63
|
-
/* @__PURE__ */
|
|
64
|
+
/* @__PURE__ */ f("div", {
|
|
64
65
|
className: "flex-1 min-w-0",
|
|
65
66
|
children: [
|
|
66
|
-
/* @__PURE__ */
|
|
67
|
+
/* @__PURE__ */ f("div", {
|
|
67
68
|
className: "flex items-center gap-1.5",
|
|
68
|
-
children: [/* @__PURE__ */
|
|
69
|
+
children: [/* @__PURE__ */ d("span", {
|
|
69
70
|
className: "text-sm text-text-primary truncate font-medium",
|
|
70
|
-
children:
|
|
71
|
-
}),
|
|
71
|
+
children: m.name
|
|
72
|
+
}), D && /* @__PURE__ */ d(s, { className: "w-3 h-3 text-text-secondary flex-shrink-0" })]
|
|
72
73
|
}),
|
|
73
|
-
/* @__PURE__ */
|
|
74
|
+
/* @__PURE__ */ f("div", {
|
|
74
75
|
className: "flex items-center gap-1.5 mt-0.5",
|
|
75
76
|
children: [
|
|
76
|
-
/* @__PURE__ */
|
|
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:
|
|
79
|
+
children: m.agentType
|
|
79
80
|
}),
|
|
80
|
-
typeof
|
|
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:
|
|
83
|
+
children: m.config.mode
|
|
83
84
|
}),
|
|
84
|
-
|
|
85
|
+
m.createdAt && /* @__PURE__ */ d("span", {
|
|
85
86
|
className: "text-xs text-text-tertiary truncate",
|
|
86
|
-
children:
|
|
87
|
+
children: a(m.createdAt)
|
|
87
88
|
})
|
|
88
89
|
]
|
|
89
90
|
}),
|
|
90
|
-
|
|
91
|
+
k.length > 0 && /* @__PURE__ */ f("div", {
|
|
91
92
|
className: "flex gap-0.5 mt-0.5 flex-wrap",
|
|
92
|
-
children: [
|
|
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)),
|
|
96
|
+
}, e)), k.length > 3 && /* @__PURE__ */ f("span", {
|
|
96
97
|
className: "text-[10px] text-text-muted",
|
|
97
|
-
children: ["+",
|
|
98
|
+
children: ["+", k.length - 3]
|
|
98
99
|
})]
|
|
99
100
|
})
|
|
100
101
|
]
|
|
101
102
|
}),
|
|
102
|
-
|
|
103
|
+
y && /* @__PURE__ */ f("div", {
|
|
103
104
|
className: "flex items-center gap-0.5 flex-shrink-0",
|
|
104
105
|
children: [
|
|
105
|
-
/* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ d("button", {
|
|
106
107
|
onClick: (e) => {
|
|
107
|
-
e.stopPropagation(),
|
|
108
|
+
e.stopPropagation(), w(m.id, m), C(m.id, m.name), T(m.id);
|
|
108
109
|
},
|
|
109
|
-
className: `p-1 rounded transition-colors ${
|
|
110
|
-
title:
|
|
111
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
114
|
+
/* @__PURE__ */ d("button", {
|
|
114
115
|
onClick: (e) => {
|
|
115
116
|
e.stopPropagation();
|
|
116
|
-
let t =
|
|
117
|
-
if (
|
|
118
|
-
let i =
|
|
119
|
-
|
|
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:
|
|
123
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
126
|
+
/* @__PURE__ */ d("button", {
|
|
126
127
|
onClick: (e) => {
|
|
127
|
-
e.stopPropagation(),
|
|
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:
|
|
131
|
-
children: /* @__PURE__ */
|
|
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 {
|
|
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":";;;;;;;;;;;AAyBA,IAAM,IAA4C;CAChD,QAAQ;CACR,MAAM;CACN,OAAO;CACP,YAAY;CACZ,YAAY;CACb;AAED,SAAgB,EAAwB,EACtC,YACA,UACA,aACA,eACA,eAC+B;CAC/B,IAAM,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,IAAK,GAAO,EACZ,IAAc,GAAsB,MAAM,EAAE,YAAY,EACxD,IAAuB,GAAsB,MAAM,EAAE,qBAAqB,EAC1E,IAAS,GAAsB,MAAM,EAAE,OAAO,EAC9C,IAAyB,GAAsB,MAAM,EAAE,uBAAuB,EAG9E,IAFO,GAAsB,MAAM,EAAE,KAAK,CAE1B,MAAM,MAAM,EAAE,cAAc,EAAQ,GAAG,EAAE,UAAU,IACnE,IAAW,EAAkB,EAAQ,WAAW,qBAChD,IAAmB,EAAQ,QAAoC,QAAqB,EAAE,EAEtF,UAAoB;AAExB,EADA,EAAqB,EAAQ,IAAI,EAAQ,EACzC,EAAY,EAAQ,IAAI,EAAQ,KAAK;;AAgCvC,QACE,kBAAC,EAAO,KAAR;EACE,QAAA;EACA,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,MAAM;GAAE,SAAS;GAAG,GAAG;GAAI;EAC3B,YAAY,EAAE,UAAU,KAAM;EAC9B,oBAAoB,EAAW,GAAK;EACpC,oBAAoB,EAAW,GAAM;EACrC,SAAS;EACT,WAAW,4EACT,IACI,uDACA;EAEN,MAAK;EACL,UAAU;EACV,YAAY,MAAM;AAChB,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,QAAK,GAAa;;YAjBzD;GAqBE,kBAAC,OAAD;IACE,WAAW,oCAAoC,KAAW,IAAa,gBAAgB;IACvF,UA7BkB,MAAwB;AAE9C,KADA,EAAE,iBAAiB,EACnB,EAAuB,EAAQ,GAAG;;cA6B9B,kBAAC,GAAD;KACE,SAAS;KACT,gBAAgB,EAAuB,EAAQ,GAAG;KAClD,WAAW,kBAAkB,EAAQ;KACrC,CAAA;IACE,CAAA;GAGN,kBAAC,QAAD;IAAM,WAAW,sCAAsC;IAAY,OAAO,EAAQ;IAAU,CAAA;GAG5F,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD;OAAM,WAAU;iBAAkD,EAAQ;OAAY,CAAA,EACrF,KAAY,kBAAC,GAAD,EAAK,WAAU,6CAA8C,CAAA,CACtE;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAQ;QACJ,CAAA;OACN,OAAQ,EAAQ,QAAoC,QAAS,YAC5D,kBAAC,QAAD;QAAM,WAAU;kBACZ,EAAQ,OAAkC;QACvC,CAAA;OAER,EAAQ,aACP,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAa,EAAQ,UAAU;QAC3B,CAAA;OAEL;;KACL,EAAK,SAAS,KACb,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACG,EAAK,MAAM,GAAG,EAAE,CAAC,KAAK,MACrB,kBAAC,QAAD;OAEE,WAAU;iBAET;OACI,EAJA,EAIA,CACP,EACD,EAAK,SAAS,KACb,kBAAC,QAAD;OAAM,WAAU;iBAAhB,CAA8C,KAAE,EAAK,SAAS,EAAS;SAErE;;KAEJ;;GAGL,KACC,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,UAAD;MACE,UA3GS,MAAwB;AAIzC,OAHA,EAAE,iBAAiB,EACnB,EAAqB,EAAQ,IAAI,EAAQ,EACzC,EAAY,EAAQ,IAAI,EAAQ,KAAK,EACrC,EAAO,EAAQ,GAAG;;MAwGV,WAAW,iCACT,IACI,gDACA;MAEN,OACE,IACI,EAAG,+CAA+C,QAAQ,GAC1D,EAAG,6CAA6C,MAAM;gBAG5D,kBAAC,GAAD,EAAK,WAAU,eAAgB,CAAA;MACxB,CAAA;KACT,kBAAC,UAAD;MACE,UA9Gc,MAAwB;AAC9C,SAAE,iBAAiB;OACnB,IAAM,IAAc,EAAK,KAAK,KAAK,EAC7B,IAAQ,OAAO,OAAO,iCAAiC,EAAY;AACzE,WAAI,MAAU,KAAM;OACpB,IAAM,IAAU,EACb,MAAM,IAAI,CACV,KAAK,MAAM,EAAE,MAAM,CAAC,CACpB,OAAO,QAAQ;AACb,SAAoB,GAAO,EAAQ,IAAI,EAAE,MAAM,GAAS,CAAC;;MAsGtD,WAAU;MACV,OAAO,EAAG,kDAAkD,YAAY;gBAExE,kBAAC,GAAD,EAAK,WAAU,eAAgB,CAAA;MACxB,CAAA;KACT,kBAAC,UAAD;MACE,UA1HY,MAAwB;AAE5C,OADA,EAAE,iBAAiB,EACnB,EAAS,EAAQ,GAAG;;MAyHZ,WAAU;MACV,OAAO,EAAG,uDAAuD,iBAAiB;gBAElF,kBAAC,GAAD,EAAQ,WAAU,eAAgB,CAAA;MAC3B,CAAA;KACL;;GAEG"}
|
|
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"}
|