@burdenoff/microfe-vibecontrols 2026.522.7 → 2026.522.8

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.
@@ -0,0 +1,237 @@
1
+ import { useTr as e } from "../../shared/hooks/useTr.js";
2
+ import { useAttachAgentToVibeMutation as t, useDetachAgentFromVibeMutation as n, useListAgentsQuery as r } from "../../generated/wspace-operations.js";
3
+ import { useVibeControlsStore as i } from "../../store/vibeControlsStore.js";
4
+ import { Card as a } from "../shared/Card.js";
5
+ import "../shared/index.js";
6
+ import { useCallback as o, useMemo as s, useState as c } from "react";
7
+ import { Check as l, ChevronDown as u, Plus as d, Search as f, Server as p, X as m } from "lucide-react";
8
+ import { jsx as h, jsxs as g } from "react/jsx-runtime";
9
+ //#region src/components/vibe/VibeAgentSwitcher.tsx
10
+ function _({ vibeId: _, attachedAgents: v, effectiveAgentId: y }) {
11
+ let b = e(), x = i((e) => e.setDefaultAgentForVibe), [S, C] = c(!1), [w, T] = c(""), [E, D] = c(!1), [O, k] = c(""), [A, j] = c(null), [M, N] = c(!1), P = v.find((e) => e.id === y) ?? v[0] ?? null, F = s(() => {
12
+ let e = w.trim().toLowerCase();
13
+ return e ? v.filter((t) => t.name.toLowerCase().includes(e) || (t.hostname ?? "").toLowerCase().includes(e) || t.id.toLowerCase().includes(e)) : v;
14
+ }, [v, w]), { data: I, refetch: L } = r({
15
+ skip: !E,
16
+ fetchPolicy: "cache-and-network"
17
+ }), R = s(() => new Set(v.map((e) => e.id)), [v]), z = s(() => {
18
+ let e = I?.vibecontrolsAgents ?? [], t = O.trim().toLowerCase();
19
+ return e.filter((e) => !R.has(e.id)).filter((e) => t ? e.name.toLowerCase().includes(t) || (e.hostname ?? "").toLowerCase().includes(t) : !0);
20
+ }, [
21
+ I,
22
+ R,
23
+ O
24
+ ]), [B] = t({
25
+ refetchQueries: ["GetVibe", "ListVibes"],
26
+ awaitRefetchQueries: !0
27
+ }), [V] = n({
28
+ refetchQueries: ["GetVibe", "ListVibes"],
29
+ awaitRefetchQueries: !0
30
+ }), H = o((e) => {
31
+ x(_, e), C(!1);
32
+ }, [x, _]), U = o(async (e) => {
33
+ N(!0), j(null);
34
+ try {
35
+ await B({ variables: { input: {
36
+ vibeId: _,
37
+ agentId: e
38
+ } } }), await L(), D(!1);
39
+ } catch (e) {
40
+ j(e instanceof Error ? e.message : String(e));
41
+ } finally {
42
+ N(!1);
43
+ }
44
+ }, [
45
+ B,
46
+ L,
47
+ _
48
+ ]), W = o(async (e) => {
49
+ if (confirm(b("vibeAgentSwitcher.detachConfirm", "Detach this agent from the vibe?"))) {
50
+ N(!0);
51
+ try {
52
+ await V({ variables: { input: {
53
+ vibeId: _,
54
+ agentId: e
55
+ } } });
56
+ } finally {
57
+ N(!1);
58
+ }
59
+ }
60
+ }, [
61
+ V,
62
+ b,
63
+ _
64
+ ]);
65
+ return /* @__PURE__ */ g(a, { children: [
66
+ /* @__PURE__ */ g("div", {
67
+ className: "p-4 border-b border-border-default flex items-center justify-between",
68
+ children: [/* @__PURE__ */ g("h3", {
69
+ className: "font-semibold text-text-primary flex items-center gap-2",
70
+ children: [/* @__PURE__ */ h(p, { className: "w-5 h-5" }), b("vibeAgentSwitcher.title", "Active agent for this vibe")]
71
+ }), /* @__PURE__ */ g("button", {
72
+ type: "button",
73
+ onClick: () => D(!0),
74
+ className: "inline-flex items-center gap-1.5 text-xs px-2.5 py-1.5 rounded-md border border-border-default text-text-primary hover:bg-bg-sunken",
75
+ disabled: M,
76
+ children: [/* @__PURE__ */ h(d, { className: "w-3.5 h-3.5" }), b("vibeAgentSwitcher.attachAnother", "Attach another")]
77
+ })]
78
+ }),
79
+ /* @__PURE__ */ g("div", {
80
+ className: "p-4 space-y-2 relative",
81
+ children: [/* @__PURE__ */ g("button", {
82
+ type: "button",
83
+ onClick: () => C((e) => !e),
84
+ className: "w-full flex items-center justify-between gap-3 px-3 py-2.5 rounded-md border border-border-default bg-bg-sunken hover:border-action-primary-bg",
85
+ "aria-haspopup": "listbox",
86
+ "aria-expanded": S,
87
+ children: [/* @__PURE__ */ g("span", {
88
+ className: "flex items-center gap-3 min-w-0",
89
+ children: [/* @__PURE__ */ h(p, { className: "w-4 h-4 text-text-secondary flex-shrink-0" }), /* @__PURE__ */ g("span", {
90
+ className: "min-w-0 text-left",
91
+ children: [/* @__PURE__ */ h("span", {
92
+ className: "block text-sm font-medium text-text-primary truncate",
93
+ children: P?.name ?? b("vibeAgentSwitcher.none", "No active agent")
94
+ }), /* @__PURE__ */ g("span", {
95
+ className: "block text-xs text-text-secondary truncate",
96
+ children: [P?.hostname ?? "—", P && (P.isActive ? " · active" : " · offline")]
97
+ })]
98
+ })]
99
+ }), /* @__PURE__ */ h(u, { className: `w-4 h-4 text-text-secondary transition-transform ${S ? "rotate-180" : ""}` })]
100
+ }), S && /* @__PURE__ */ g("div", {
101
+ className: "absolute left-4 right-4 z-30 mt-1 rounded-md border border-border-default bg-bg-elevated shadow-lg",
102
+ children: [/* @__PURE__ */ g("div", {
103
+ className: "flex items-center gap-2 px-3 py-2 border-b border-border-subtle",
104
+ children: [/* @__PURE__ */ h(f, { className: "w-4 h-4 text-text-secondary" }), /* @__PURE__ */ h("input", {
105
+ type: "text",
106
+ value: w,
107
+ onChange: (e) => T(e.target.value),
108
+ placeholder: b("vibeAgentSwitcher.searchPlaceholder", "Search agents…"),
109
+ className: "w-full bg-transparent text-sm text-text-primary outline-none",
110
+ autoFocus: !0
111
+ })]
112
+ }), /* @__PURE__ */ h("ul", {
113
+ role: "listbox",
114
+ className: "max-h-64 overflow-y-auto py-1",
115
+ children: F.length === 0 ? /* @__PURE__ */ h("li", {
116
+ className: "px-3 py-2 text-xs text-text-secondary",
117
+ children: b("vibeAgentSwitcher.noMatch", "No agents match your search.")
118
+ }) : F.map((e) => {
119
+ let t = e.id === y;
120
+ return /* @__PURE__ */ g("li", {
121
+ className: "flex items-center",
122
+ children: [/* @__PURE__ */ g("button", {
123
+ type: "button",
124
+ role: "option",
125
+ "aria-selected": t,
126
+ onClick: () => H(e.id),
127
+ className: `flex-1 flex items-center justify-between gap-3 px-3 py-2 text-left text-sm hover:bg-bg-sunken ${t ? "bg-bg-sunken" : ""}`,
128
+ children: [/* @__PURE__ */ g("span", {
129
+ className: "flex items-center gap-2 min-w-0",
130
+ children: [/* @__PURE__ */ h(p, { className: "w-4 h-4 text-text-secondary flex-shrink-0" }), /* @__PURE__ */ g("span", {
131
+ className: "min-w-0",
132
+ children: [/* @__PURE__ */ h("span", {
133
+ className: "block text-text-primary truncate",
134
+ children: e.name
135
+ }), /* @__PURE__ */ g("span", {
136
+ className: "block text-xs text-text-secondary truncate",
137
+ children: [
138
+ e.hostname ?? "—",
139
+ " ",
140
+ e.isActive ? "· active" : "· offline"
141
+ ]
142
+ })]
143
+ })]
144
+ }), t && /* @__PURE__ */ h(l, { className: "w-4 h-4 text-action-primary-bg" })]
145
+ }), /* @__PURE__ */ h("button", {
146
+ type: "button",
147
+ onClick: () => W(e.id),
148
+ disabled: M,
149
+ title: b("vibeAgentSwitcher.detach", "Detach from vibe"),
150
+ className: "px-2 text-text-secondary hover:text-status-error-text",
151
+ children: /* @__PURE__ */ h(m, { className: "w-4 h-4" })
152
+ })]
153
+ }, e.id);
154
+ })
155
+ })]
156
+ })]
157
+ }),
158
+ E && /* @__PURE__ */ h("div", {
159
+ role: "dialog",
160
+ "aria-modal": "true",
161
+ className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4",
162
+ onClick: (e) => {
163
+ e.target === e.currentTarget && D(!1);
164
+ },
165
+ children: /* @__PURE__ */ g("div", {
166
+ className: "w-full max-w-md rounded-lg bg-bg-elevated border border-border-default shadow-xl",
167
+ children: [
168
+ /* @__PURE__ */ g("div", {
169
+ className: "flex items-center justify-between px-5 py-4 border-b border-border-subtle",
170
+ children: [/* @__PURE__ */ h("h2", {
171
+ className: "text-base font-semibold text-text-primary",
172
+ children: b("vibeAgentSwitcher.attachTitle", "Attach an additional agent")
173
+ }), /* @__PURE__ */ h("button", {
174
+ type: "button",
175
+ onClick: () => D(!1),
176
+ className: "text-text-secondary hover:text-text-primary",
177
+ "aria-label": b("common.close", "Close"),
178
+ children: /* @__PURE__ */ h(m, { className: "w-4 h-4" })
179
+ })]
180
+ }),
181
+ /* @__PURE__ */ h("div", {
182
+ className: "px-5 py-3 border-b border-border-subtle",
183
+ children: /* @__PURE__ */ g("div", {
184
+ className: "flex items-center gap-2",
185
+ children: [/* @__PURE__ */ h(f, { className: "w-4 h-4 text-text-secondary" }), /* @__PURE__ */ h("input", {
186
+ type: "text",
187
+ value: O,
188
+ onChange: (e) => k(e.target.value),
189
+ placeholder: b("vibeAgentSwitcher.searchPlaceholder", "Search agents…"),
190
+ className: "w-full bg-transparent text-sm text-text-primary outline-none",
191
+ autoFocus: !0
192
+ })]
193
+ })
194
+ }),
195
+ /* @__PURE__ */ g("div", {
196
+ className: "px-2 py-2 max-h-[60vh] overflow-y-auto",
197
+ children: [z.length === 0 ? /* @__PURE__ */ h("p", {
198
+ className: "text-sm text-text-secondary px-3 py-2",
199
+ children: b("vibeAgentSwitcher.noCandidates", "No unattached agents available. Register a new agent first.")
200
+ }) : /* @__PURE__ */ h("ul", {
201
+ className: "space-y-1",
202
+ children: z.map((e) => /* @__PURE__ */ h("li", { children: /* @__PURE__ */ g("button", {
203
+ type: "button",
204
+ onClick: () => U(e.id),
205
+ disabled: M,
206
+ className: "w-full flex items-center justify-between gap-3 px-3 py-2.5 rounded-md border border-border-subtle hover:border-border-default hover:bg-action-ghost-bg-hover text-left disabled:opacity-60",
207
+ children: [/* @__PURE__ */ g("span", {
208
+ className: "flex items-center gap-3 min-w-0",
209
+ children: [/* @__PURE__ */ h(p, { className: "w-4 h-4 text-text-secondary flex-shrink-0" }), /* @__PURE__ */ g("span", {
210
+ className: "min-w-0",
211
+ children: [/* @__PURE__ */ h("span", {
212
+ className: "block text-sm font-medium text-text-primary truncate",
213
+ children: e.name
214
+ }), /* @__PURE__ */ g("span", {
215
+ className: "block text-xs text-text-secondary truncate",
216
+ children: [e.hostname || "—", e.isActive ? " · active" : " · inactive"]
217
+ })]
218
+ })]
219
+ }), /* @__PURE__ */ h("span", {
220
+ className: "text-xs text-text-tertiary",
221
+ children: b("vibeAgentSwitcher.attach", "Attach")
222
+ })]
223
+ }) }, e.id))
224
+ }), A && /* @__PURE__ */ h("p", {
225
+ className: "mt-2 px-3 text-sm text-status-error-text",
226
+ children: A
227
+ })]
228
+ })
229
+ ]
230
+ })
231
+ })
232
+ ] });
233
+ }
234
+ //#endregion
235
+ export { _ as VibeAgentSwitcher };
236
+
237
+ //# sourceMappingURL=VibeAgentSwitcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VibeAgentSwitcher.js","names":[],"sources":["../../../src/components/vibe/VibeAgentSwitcher.tsx"],"sourcesContent":["/**\n * VibeAgentSwitcher — inline switcher + attach-more affordance shown on the\n * Vibe detail Overview tab once at least one agent is attached.\n *\n * Why this exists: a vibe can carry many agents (every collaborator brings\n * their own host/dev VM alongside shared env agents). Without a top-level\n * switcher, the \"effective agent\" chosen by the auto-pick heuristic is\n * invisible and unswitchable from the detail page, and there's no way to\n * attach a *second* agent without leaving for the agents tab. This card:\n *\n * 1. Names the active agent for the current user on this vibe.\n * 2. Lists every attached agent in a searchable dropdown — choosing one\n * writes to the per-vibe default store slot, persisted across reloads.\n * 3. Surfaces \"Attach another agent\" so users discover the multi-attach\n * flow without bouncing tabs.\n * 4. Surfaces \"Detach\" per agent (owner-scoped, no peer detaches).\n */\nimport { useMemo, useState, useCallback } from 'react';\nimport { Check, ChevronDown, Plus, Search, Server, X } from 'lucide-react';\nimport { Card } from '@/components/shared';\nimport {\n useAttachAgentToVibeMutation,\n useDetachAgentFromVibeMutation,\n useListAgentsQuery,\n type ListAgentsQuery,\n} from '@/generated/wspace-operations';\n\ntype ListAgent = NonNullable<ListAgentsQuery['vibecontrolsAgents']>[number];\nimport { useVibeControlsStore } from '@/store/vibeControlsStore';\nimport { useTr } from '@/shared/hooks/useTr';\n\nexport interface AttachedAgent {\n id: string;\n name: string;\n hostname?: string | null;\n isActive: boolean;\n ownerUserId?: string | null;\n tunnelUrl?: string | null;\n}\n\ninterface Props {\n vibeId: string;\n attachedAgents: ReadonlyArray<AttachedAgent>;\n effectiveAgentId: string | null;\n}\n\nexport function VibeAgentSwitcher({ vibeId, attachedAgents, effectiveAgentId }: Props) {\n const tr = useTr();\n const setDefault = useVibeControlsStore((s) => s.setDefaultAgentForVibe);\n\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const [attachOpen, setAttachOpen] = useState(false);\n const [attachQuery, setAttachQuery] = useState('');\n const [attachError, setAttachError] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n\n const active = attachedAgents.find((a) => a.id === effectiveAgentId) ?? attachedAgents[0] ?? null;\n\n const filtered = useMemo(() => {\n const q = query.trim().toLowerCase();\n if (!q) return attachedAgents;\n return attachedAgents.filter(\n (a) =>\n a.name.toLowerCase().includes(q) ||\n (a.hostname ?? '').toLowerCase().includes(q) ||\n a.id.toLowerCase().includes(q)\n );\n }, [attachedAgents, query]);\n\n const { data: agentsData, refetch: refetchAgents } = useListAgentsQuery({\n skip: !attachOpen,\n fetchPolicy: 'cache-and-network',\n });\n const attachedIds = useMemo(() => new Set(attachedAgents.map((a) => a.id)), [attachedAgents]);\n const candidates = useMemo(() => {\n const all = agentsData?.vibecontrolsAgents ?? [];\n const q = attachQuery.trim().toLowerCase();\n return all\n .filter((a: ListAgent) => !attachedIds.has(a.id))\n .filter((a: ListAgent) =>\n q ? a.name.toLowerCase().includes(q) || (a.hostname ?? '').toLowerCase().includes(q) : true\n );\n }, [agentsData, attachedIds, attachQuery]);\n\n const [attach] = useAttachAgentToVibeMutation({\n refetchQueries: ['GetVibe', 'ListVibes'],\n awaitRefetchQueries: true,\n });\n const [detach] = useDetachAgentFromVibeMutation({\n refetchQueries: ['GetVibe', 'ListVibes'],\n awaitRefetchQueries: true,\n });\n\n const handlePick = useCallback(\n (agentId: string) => {\n setDefault(vibeId, agentId);\n setOpen(false);\n },\n [setDefault, vibeId]\n );\n\n const handleAttach = useCallback(\n async (agentId: string) => {\n setBusy(true);\n setAttachError(null);\n try {\n await attach({ variables: { input: { vibeId, agentId } } });\n await refetchAgents();\n setAttachOpen(false);\n } catch (err) {\n setAttachError(err instanceof Error ? err.message : String(err));\n } finally {\n setBusy(false);\n }\n },\n [attach, refetchAgents, vibeId]\n );\n\n const handleDetach = useCallback(\n async (agentId: string) => {\n if (!confirm(tr('vibeAgentSwitcher.detachConfirm', 'Detach this agent from the vibe?'))) {\n return;\n }\n setBusy(true);\n try {\n await detach({ variables: { input: { vibeId, agentId } } });\n } finally {\n setBusy(false);\n }\n },\n [detach, tr, vibeId]\n );\n\n return (\n <Card>\n <div className=\"p-4 border-b border-border-default flex items-center justify-between\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Server className=\"w-5 h-5\" />\n {tr('vibeAgentSwitcher.title', 'Active agent for this vibe')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setAttachOpen(true)}\n className=\"inline-flex items-center gap-1.5 text-xs px-2.5 py-1.5 rounded-md border border-border-default text-text-primary hover:bg-bg-sunken\"\n disabled={busy}\n >\n <Plus className=\"w-3.5 h-3.5\" />\n {tr('vibeAgentSwitcher.attachAnother', 'Attach another')}\n </button>\n </div>\n\n <div className=\"p-4 space-y-2 relative\">\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n className=\"w-full flex items-center justify-between gap-3 px-3 py-2.5 rounded-md border border-border-default bg-bg-sunken hover:border-action-primary-bg\"\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n >\n <span className=\"flex items-center gap-3 min-w-0\">\n <Server className=\"w-4 h-4 text-text-secondary flex-shrink-0\" />\n <span className=\"min-w-0 text-left\">\n <span className=\"block text-sm font-medium text-text-primary truncate\">\n {active?.name ?? tr('vibeAgentSwitcher.none', 'No active agent')}\n </span>\n <span className=\"block text-xs text-text-secondary truncate\">\n {active?.hostname ?? '—'}\n {active && (active.isActive ? ' · active' : ' · offline')}\n </span>\n </span>\n </span>\n <ChevronDown\n className={`w-4 h-4 text-text-secondary transition-transform ${open ? 'rotate-180' : ''}`}\n />\n </button>\n\n {open && (\n <div className=\"absolute left-4 right-4 z-30 mt-1 rounded-md border border-border-default bg-bg-elevated shadow-lg\">\n <div className=\"flex items-center gap-2 px-3 py-2 border-b border-border-subtle\">\n <Search className=\"w-4 h-4 text-text-secondary\" />\n <input\n type=\"text\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={tr('vibeAgentSwitcher.searchPlaceholder', 'Search agents…')}\n className=\"w-full bg-transparent text-sm text-text-primary outline-none\"\n autoFocus\n />\n </div>\n <ul role=\"listbox\" className=\"max-h-64 overflow-y-auto py-1\">\n {filtered.length === 0 ? (\n <li className=\"px-3 py-2 text-xs text-text-secondary\">\n {tr('vibeAgentSwitcher.noMatch', 'No agents match your search.')}\n </li>\n ) : (\n filtered.map((a) => {\n const isActive = a.id === effectiveAgentId;\n return (\n <li key={a.id} className=\"flex items-center\">\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={isActive}\n onClick={() => handlePick(a.id)}\n className={`flex-1 flex items-center justify-between gap-3 px-3 py-2 text-left text-sm hover:bg-bg-sunken ${isActive ? 'bg-bg-sunken' : ''}`}\n >\n <span className=\"flex items-center gap-2 min-w-0\">\n <Server className=\"w-4 h-4 text-text-secondary flex-shrink-0\" />\n <span className=\"min-w-0\">\n <span className=\"block text-text-primary truncate\">{a.name}</span>\n <span className=\"block text-xs text-text-secondary truncate\">\n {a.hostname ?? '—'} {a.isActive ? '· active' : '· offline'}\n </span>\n </span>\n </span>\n {isActive && <Check className=\"w-4 h-4 text-action-primary-bg\" />}\n </button>\n <button\n type=\"button\"\n onClick={() => handleDetach(a.id)}\n disabled={busy}\n title={tr('vibeAgentSwitcher.detach', 'Detach from vibe')}\n className=\"px-2 text-text-secondary hover:text-status-error-text\"\n >\n <X className=\"w-4 h-4\" />\n </button>\n </li>\n );\n })\n )}\n </ul>\n </div>\n )}\n </div>\n\n {attachOpen && (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n onClick={(e) => {\n if (e.target === e.currentTarget) setAttachOpen(false);\n }}\n >\n <div className=\"w-full max-w-md rounded-lg bg-bg-elevated border border-border-default shadow-xl\">\n <div className=\"flex items-center justify-between px-5 py-4 border-b border-border-subtle\">\n <h2 className=\"text-base font-semibold text-text-primary\">\n {tr('vibeAgentSwitcher.attachTitle', 'Attach an additional agent')}\n </h2>\n <button\n type=\"button\"\n onClick={() => setAttachOpen(false)}\n className=\"text-text-secondary hover:text-text-primary\"\n aria-label={tr('common.close', 'Close')}\n >\n <X className=\"w-4 h-4\" />\n </button>\n </div>\n <div className=\"px-5 py-3 border-b border-border-subtle\">\n <div className=\"flex items-center gap-2\">\n <Search className=\"w-4 h-4 text-text-secondary\" />\n <input\n type=\"text\"\n value={attachQuery}\n onChange={(e) => setAttachQuery(e.target.value)}\n placeholder={tr('vibeAgentSwitcher.searchPlaceholder', 'Search agents…')}\n className=\"w-full bg-transparent text-sm text-text-primary outline-none\"\n autoFocus\n />\n </div>\n </div>\n <div className=\"px-2 py-2 max-h-[60vh] overflow-y-auto\">\n {candidates.length === 0 ? (\n <p className=\"text-sm text-text-secondary px-3 py-2\">\n {tr(\n 'vibeAgentSwitcher.noCandidates',\n 'No unattached agents available. Register a new agent first.'\n )}\n </p>\n ) : (\n <ul className=\"space-y-1\">\n {candidates.map((a: ListAgent) => (\n <li key={a.id}>\n <button\n type=\"button\"\n onClick={() => handleAttach(a.id)}\n disabled={busy}\n className=\"w-full flex items-center justify-between gap-3 px-3 py-2.5 rounded-md border border-border-subtle hover:border-border-default hover:bg-action-ghost-bg-hover text-left disabled:opacity-60\"\n >\n <span className=\"flex items-center gap-3 min-w-0\">\n <Server className=\"w-4 h-4 text-text-secondary flex-shrink-0\" />\n <span className=\"min-w-0\">\n <span className=\"block text-sm font-medium text-text-primary truncate\">\n {a.name}\n </span>\n <span className=\"block text-xs text-text-secondary truncate\">\n {a.hostname || '—'}\n {a.isActive ? ' · active' : ' · inactive'}\n </span>\n </span>\n </span>\n <span className=\"text-xs text-text-tertiary\">\n {tr('vibeAgentSwitcher.attach', 'Attach')}\n </span>\n </button>\n </li>\n ))}\n </ul>\n )}\n {attachError && (\n <p className=\"mt-2 px-3 text-sm text-status-error-text\">{attachError}</p>\n )}\n </div>\n </div>\n </div>\n )}\n </Card>\n );\n}\n"],"mappings":"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"}
@@ -49,9 +49,9 @@ var _ = ({ vibe: _, onOpen: v, onEdit: y, onArchive: b, onActivate: x, onOpenInE
49
49
  children: [/* @__PURE__ */ h("h3", {
50
50
  className: "font-semibold text-text-primary truncate text-sm sm:text-base",
51
51
  children: _.name
52
- }), /* @__PURE__ */ h("p", {
52
+ }), _.description && /* @__PURE__ */ h("p", {
53
53
  className: "text-xs sm:text-sm text-text-secondary truncate",
54
- children: _.type
54
+ children: _.description
55
55
  })]
56
56
  })
57
57
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"VibeCard.js","names":[],"sources":["../../../src/components/vibes/VibeCard.tsx"],"sourcesContent":["import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport type { FC } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport {\n FolderOpen,\n GitBranch,\n MoreVertical,\n Play,\n Archive,\n Settings,\n Tag,\n ExternalLink,\n} from 'lucide-react';\nimport { useState } from 'react';\nimport type { Vibe } from './types';\nimport { vibeTypeIcons } from './icons';\nimport { StatusBadge } from '../shared/StatusBadge';\nimport { SelectionCheckbox } from '../shared/SelectionCheckbox';\n\nexport interface VibeCardProps {\n vibe: Vibe;\n onOpen?: (vibe: Vibe) => void;\n onEdit?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n className?: string;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}\n\n/**\n * VibeCard - Display project/vibe information\n */\nexport const VibeCard: FC<VibeCardProps> = ({\n vibe,\n onOpen,\n onEdit,\n onArchive,\n onActivate,\n onOpenInEditor,\n className = '',\n selected = false,\n onToggleSelect,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const [showMenu, setShowMenu] = useState(false);\n const Icon = vibeTypeIcons[vibe.type] || FolderOpen;\n\n return (\n <motion.div\n whileHover={{ y: -2, transition: { duration: 0.15, ease: [0.4, 0, 0.2, 1] } }}\n whileTap={{ scale: 0.98 }}\n className={`bg-bg-surface border rounded-lg p-4 hover:border-border-strong hover:shadow-md transition-all cursor-pointer ${\n selected\n ? 'border-action-primary-bg ring-1 ring-action-primary-bg/25'\n : 'border-border-default'\n } ${className}`}\n onClick={() => onOpen?.(vibe)}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-start gap-2 sm:gap-3 min-w-0 flex-1\">\n {onToggleSelect && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selected}\n onChange={onToggleSelect}\n ariaLabel={`Select vibe ${vibe.name}`}\n className=\"mt-2\"\n />\n </div>\n )}\n <div className=\"flex-shrink-0 w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-action-primary-bg/10 flex items-center justify-center\">\n <Icon className=\"w-4 h-4 sm:w-5 sm:h-5 text-action-primary-bg\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"font-semibold text-text-primary truncate text-sm sm:text-base\">\n {vibe.name}\n </h3>\n <p className=\"text-xs sm:text-sm text-text-secondary truncate\">{vibe.type}</p>\n </div>\n </div>\n {/* Status and Actions - always visible */}\n <div className=\"flex items-center gap-1 sm:gap-2 flex-shrink-0\">\n <StatusBadge status={vibe.status} />\n {(onEdit || onArchive || onActivate || onOpenInEditor) && (\n <div className=\"relative\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"p-1 sm:p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n >\n <MoreVertical className=\"w-4 h-4 text-text-secondary\" />\n </button>\n <AnimatePresence>\n {showMenu && (\n <motion.div\n initial={{ opacity: 0, scale: 0.95, y: -4 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.95, y: -4 }}\n transition={{ duration: 0.15 }}\n className=\"absolute right-0 mt-1 w-40 bg-bg-surface border border-border-default rounded-lg shadow-lg z-10\"\n >\n {onActivate && vibe.status !== 'ACTIVE' && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onActivate(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg\"\n >\n <Play className=\"w-4 h-4\" />\n Activate\n </motion.button>\n )}\n {onEdit && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onEdit(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Settings className=\"w-4 h-4\" />\n Edit\n </motion.button>\n )}\n {onOpenInEditor && vibe.path && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onOpenInEditor(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <ExternalLink className=\"w-4 h-4\" />\n Open in VS Code\n </motion.button>\n )}\n {onArchive && vibe.status !== 'ARCHIVED' && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onArchive(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-b-lg\"\n >\n <Archive className=\"w-4 h-4\" />\n Archive\n </motion.button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n )}\n </div>\n </div>\n\n {vibe.description && (\n <p className=\"mt-2 text-sm text-text-secondary line-clamp-2\">{vibe.description}</p>\n )}\n\n {vibe.path && (\n <div className=\"mt-3 text-xs text-text-secondary font-mono bg-bg-sunken p-2 rounded truncate\">\n {vibe.path}\n </div>\n )}\n\n {vibe.gitBranch && (\n <div className=\"mt-2 flex items-center gap-2 text-sm text-text-secondary\">\n <GitBranch className=\"w-4 h-4\" />\n <span className=\"truncate\">{vibe.gitBranch}</span>\n {vibe.gitStatus && vibe.gitStatus !== 'clean' && (\n <span className=\"px-1.5 py-0.5 text-xs bg-status-warning-bg text-status-warning-text rounded\">\n {vibe.gitStatus}\n </span>\n )}\n </div>\n )}\n\n {vibe.tags && vibe.tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1\">\n {vibe.tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"w-3 h-3\" />\n {tag}\n </span>\n ))}\n {vibe.tags.length > 3 && (\n <span className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{vibe.tags.length - 3}\n </span>\n )}\n </div>\n )}\n </motion.div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"VibeCard.js","names":[],"sources":["../../../src/components/vibes/VibeCard.tsx"],"sourcesContent":["import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport type { FC } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport {\n FolderOpen,\n GitBranch,\n MoreVertical,\n Play,\n Archive,\n Settings,\n Tag,\n ExternalLink,\n} from 'lucide-react';\nimport { useState } from 'react';\nimport type { Vibe } from './types';\nimport { vibeTypeIcons } from './icons';\nimport { StatusBadge } from '../shared/StatusBadge';\nimport { SelectionCheckbox } from '../shared/SelectionCheckbox';\n\nexport interface VibeCardProps {\n vibe: Vibe;\n onOpen?: (vibe: Vibe) => void;\n onEdit?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n className?: string;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}\n\n/**\n * VibeCard - Display project/vibe information\n */\nexport const VibeCard: FC<VibeCardProps> = ({\n vibe,\n onOpen,\n onEdit,\n onArchive,\n onActivate,\n onOpenInEditor,\n className = '',\n selected = false,\n onToggleSelect,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const [showMenu, setShowMenu] = useState(false);\n const Icon = vibeTypeIcons[vibe.type] || FolderOpen;\n\n return (\n <motion.div\n whileHover={{ y: -2, transition: { duration: 0.15, ease: [0.4, 0, 0.2, 1] } }}\n whileTap={{ scale: 0.98 }}\n className={`bg-bg-surface border rounded-lg p-4 hover:border-border-strong hover:shadow-md transition-all cursor-pointer ${\n selected\n ? 'border-action-primary-bg ring-1 ring-action-primary-bg/25'\n : 'border-border-default'\n } ${className}`}\n onClick={() => onOpen?.(vibe)}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-start gap-2 sm:gap-3 min-w-0 flex-1\">\n {onToggleSelect && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selected}\n onChange={onToggleSelect}\n ariaLabel={`Select vibe ${vibe.name}`}\n className=\"mt-2\"\n />\n </div>\n )}\n <div className=\"flex-shrink-0 w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-action-primary-bg/10 flex items-center justify-center\">\n <Icon className=\"w-4 h-4 sm:w-5 sm:h-5 text-action-primary-bg\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"font-semibold text-text-primary truncate text-sm sm:text-base\">\n {vibe.name}\n </h3>\n {vibe.description && (\n <p className=\"text-xs sm:text-sm text-text-secondary truncate\">{vibe.description}</p>\n )}\n </div>\n </div>\n {/* Status and Actions - always visible */}\n <div className=\"flex items-center gap-1 sm:gap-2 flex-shrink-0\">\n <StatusBadge status={vibe.status} />\n {(onEdit || onArchive || onActivate || onOpenInEditor) && (\n <div className=\"relative\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"p-1 sm:p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n >\n <MoreVertical className=\"w-4 h-4 text-text-secondary\" />\n </button>\n <AnimatePresence>\n {showMenu && (\n <motion.div\n initial={{ opacity: 0, scale: 0.95, y: -4 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.95, y: -4 }}\n transition={{ duration: 0.15 }}\n className=\"absolute right-0 mt-1 w-40 bg-bg-surface border border-border-default rounded-lg shadow-lg z-10\"\n >\n {onActivate && vibe.status !== 'ACTIVE' && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onActivate(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg\"\n >\n <Play className=\"w-4 h-4\" />\n Activate\n </motion.button>\n )}\n {onEdit && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onEdit(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Settings className=\"w-4 h-4\" />\n Edit\n </motion.button>\n )}\n {onOpenInEditor && vibe.path && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onOpenInEditor(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <ExternalLink className=\"w-4 h-4\" />\n Open in VS Code\n </motion.button>\n )}\n {onArchive && vibe.status !== 'ARCHIVED' && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onArchive(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-b-lg\"\n >\n <Archive className=\"w-4 h-4\" />\n Archive\n </motion.button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n )}\n </div>\n </div>\n\n {vibe.description && (\n <p className=\"mt-2 text-sm text-text-secondary line-clamp-2\">{vibe.description}</p>\n )}\n\n {vibe.path && (\n <div className=\"mt-3 text-xs text-text-secondary font-mono bg-bg-sunken p-2 rounded truncate\">\n {vibe.path}\n </div>\n )}\n\n {vibe.gitBranch && (\n <div className=\"mt-2 flex items-center gap-2 text-sm text-text-secondary\">\n <GitBranch className=\"w-4 h-4\" />\n <span className=\"truncate\">{vibe.gitBranch}</span>\n {vibe.gitStatus && vibe.gitStatus !== 'clean' && (\n <span className=\"px-1.5 py-0.5 text-xs bg-status-warning-bg text-status-warning-text rounded\">\n {vibe.gitStatus}\n </span>\n )}\n </div>\n )}\n\n {vibe.tags && vibe.tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1\">\n {vibe.tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"w-3 h-3\" />\n {tag}\n </span>\n ))}\n {vibe.tags.length > 3 && (\n <span className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{vibe.tags.length - 3}\n </span>\n )}\n </div>\n )}\n </motion.div>\n );\n};\n"],"mappings":"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"}
@@ -42,25 +42,18 @@ function v({ vibe: e, onOpen: t, onActivate: a, onOpenInEditor: u, onArchive: f,
42
42
  }),
43
43
  /* @__PURE__ */ _("div", {
44
44
  className: "mt-3 flex flex-wrap items-center gap-x-4 gap-y-2 text-xs text-text-secondary",
45
- children: [
46
- /* @__PURE__ */ g("span", {
47
- className: "font-medium",
48
- children: e.type
49
- }),
50
- e.gitBranch && /* @__PURE__ */ _("span", {
51
- className: "flex items-center gap-1",
52
- children: [/* @__PURE__ */ g(l, { className: "w-3 h-3" }), e.gitBranch]
53
- }),
54
- e.tags && e.tags.length > 0 && /* @__PURE__ */ _("span", {
55
- className: "flex items-center gap-1",
56
- children: [
57
- /* @__PURE__ */ g(m, { className: "w-3 h-3" }),
58
- e.tags.length,
59
- " tag",
60
- e.tags.length === 1 ? "" : "s"
61
- ]
62
- })
63
- ]
45
+ children: [e.gitBranch && /* @__PURE__ */ _("span", {
46
+ className: "flex items-center gap-1",
47
+ children: [/* @__PURE__ */ g(l, { className: "w-3 h-3" }), e.gitBranch]
48
+ }), e.tags && e.tags.length > 0 && /* @__PURE__ */ _("span", {
49
+ className: "flex items-center gap-1",
50
+ children: [
51
+ /* @__PURE__ */ g(m, { className: "w-3 h-3" }),
52
+ e.tags.length,
53
+ " tag",
54
+ e.tags.length === 1 ? "" : "s"
55
+ ]
56
+ })]
64
57
  }),
65
58
  e.path && /* @__PURE__ */ g("div", {
66
59
  className: "mt-2 text-xs font-mono text-text-muted truncate",
@@ -131,13 +124,6 @@ function y({ vibe: e, onOpen: t, onEdit: f, onArchive: h, onActivate: v, onOpenI
131
124
  })]
132
125
  })
133
126
  }),
134
- /* @__PURE__ */ g("td", {
135
- className: "px-4 py-3",
136
- children: /* @__PURE__ */ g("span", {
137
- className: "text-sm text-text-secondary",
138
- children: e.type
139
- })
140
- }),
141
127
  /* @__PURE__ */ g("td", {
142
128
  className: "px-4 py-3",
143
129
  children: /* @__PURE__ */ g(n, { status: e.status })
@@ -276,10 +262,6 @@ function b({ vibes: n, onOpen: i, onEdit: a, onArchive: o, onActivate: s, onOpen
276
262
  className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
277
263
  children: "Name"
278
264
  }),
279
- /* @__PURE__ */ g("th", {
280
- className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
281
- children: "Type"
282
- }),
283
265
  /* @__PURE__ */ g("th", {
284
266
  className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
285
267
  children: "Status"
@@ -1 +1 @@
1
- {"version":3,"file":"VibeList.js","names":[],"sources":["../../../src/components/vibes/VibeList.tsx"],"sourcesContent":["import type { Vibe } from './types';\nimport { vibeTypeIcons } from './icons';\nimport { StatusBadge } from '../shared/StatusBadge';\nimport { EmptyState } from '../shared/EmptyState';\nimport { SelectionCheckbox } from '../shared/SelectionCheckbox';\nimport {\n FolderOpen,\n Plus,\n GitBranch,\n Tag,\n MoreVertical,\n Play,\n Archive,\n Settings,\n ExternalLink,\n} from 'lucide-react';\nimport { useState } from 'react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface VibeListProps {\n vibes: Vibe[];\n onOpen?: (vibe: Vibe) => void;\n onEdit?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n onCreateNew?: () => void;\n isLoading?: boolean;\n selectedVibeIds?: Set<string>;\n onToggleSelect?: (vibe: Vibe, checked: boolean) => void;\n onToggleAllVisible?: (checked: boolean) => void;\n allVisibleSelected?: boolean;\n partiallySelected?: boolean;\n}\n\n/**\n * Mobile card view for a single vibe\n */\nfunction VibeListCard({\n vibe,\n onOpen,\n onActivate,\n onOpenInEditor,\n onArchive,\n selected,\n onToggleSelect,\n}: {\n vibe: Vibe;\n onOpen?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}) {\n const Icon = vibeTypeIcons[vibe.type] || FolderOpen;\n\n return (\n <div\n className=\"p-4 border border-border-default rounded-lg bg-bg-surface hover:bg-bg-sunken/50 cursor-pointer transition-colors\"\n onClick={() => onOpen?.(vibe)}\n >\n {/* Header: Icon, Name, Status */}\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3 min-w-0 flex-1\">\n {onToggleSelect && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={!!selected}\n onChange={onToggleSelect}\n ariaLabel={`Select vibe ${vibe.name}`}\n />\n </div>\n )}\n <Icon className=\"w-5 h-5 text-action-primary-bg flex-shrink-0 mt-0.5\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{vibe.name}</p>\n {vibe.description && (\n <p className=\"text-xs text-text-muted truncate mt-0.5\">{vibe.description}</p>\n )}\n </div>\n </div>\n <StatusBadge status={vibe.status} />\n </div>\n\n {/* Meta info row */}\n <div className=\"mt-3 flex flex-wrap items-center gap-x-4 gap-y-2 text-xs text-text-secondary\">\n <span className=\"font-medium\">{vibe.type}</span>\n {vibe.gitBranch && (\n <span className=\"flex items-center gap-1\">\n <GitBranch className=\"w-3 h-3\" />\n {vibe.gitBranch}\n </span>\n )}\n {vibe.tags && vibe.tags.length > 0 && (\n <span className=\"flex items-center gap-1\">\n <Tag className=\"w-3 h-3\" />\n {vibe.tags.length} tag{vibe.tags.length !== 1 ? 's' : ''}\n </span>\n )}\n </div>\n\n {/* Path (if exists) */}\n {vibe.path && (\n <div className=\"mt-2 text-xs font-mono text-text-muted truncate\">{vibe.path}</div>\n )}\n\n {/* Actions */}\n <div className=\"mt-3 flex items-center gap-2 justify-end border-t border-border-default pt-3\">\n {onActivate && vibe.status !== 'ACTIVE' && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onActivate(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Activate\"\n >\n <Play className=\"w-4 h-4 text-text-secondary\" />\n </button>\n )}\n {onOpenInEditor && vibe.path && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onOpenInEditor(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Open in VS Code\"\n >\n <ExternalLink className=\"w-4 h-4 text-text-secondary\" />\n </button>\n )}\n {onArchive && vibe.status !== 'ARCHIVED' && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onArchive(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Archive\"\n >\n <Archive className=\"w-4 h-4 text-text-secondary\" />\n </button>\n )}\n </div>\n </div>\n );\n}\n\nfunction VibeRow({\n vibe,\n onOpen,\n onEdit,\n onArchive,\n onActivate,\n onOpenInEditor,\n selected,\n onToggleSelect,\n}: {\n vibe: Vibe;\n onOpen?: (vibe: Vibe) => void;\n onEdit?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}) {\n const [showMenu, setShowMenu] = useState(false);\n const Icon = vibeTypeIcons[vibe.type] || FolderOpen;\n\n return (\n <tr\n className={`border-b border-border-default hover:bg-bg-sunken/50 cursor-pointer transition-colors ${\n selected ? 'bg-bg-sunken/40' : ''\n }`}\n onClick={() => onOpen?.(vibe)}\n >\n <td className=\"px-4 py-3\">\n {onToggleSelect && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={!!selected}\n onChange={onToggleSelect}\n ariaLabel={`Select vibe ${vibe.name}`}\n />\n </div>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <Icon className=\"w-4 h-4 text-action-primary-bg shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{vibe.name}</p>\n {vibe.description && (\n <p className=\"text-xs text-text-muted truncate max-w-[250px]\">{vibe.description}</p>\n )}\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-sm text-text-secondary\">{vibe.type}</span>\n </td>\n <td className=\"px-4 py-3\">\n <StatusBadge status={vibe.status} />\n </td>\n <td className=\"px-4 py-3\">\n {vibe.path ? (\n <span className=\"text-xs font-mono text-text-muted truncate block max-w-[180px]\">\n {vibe.path}\n </span>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {vibe.gitBranch ? (\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <GitBranch className=\"w-3 h-3\" />\n <span className=\"truncate max-w-[100px]\">{vibe.gitBranch}</span>\n </div>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {vibe.tags && vibe.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {vibe.tags.slice(0, 2).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"w-2.5 h-2.5\" />\n {tag}\n </span>\n ))}\n {vibe.tags.length > 2 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{vibe.tags.length - 2}\n </span>\n )}\n </div>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1 justify-end\">\n {(onEdit || onArchive || onActivate || onOpenInEditor) && (\n <div className=\"relative\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n >\n <MoreVertical className=\"w-3.5 h-3.5 text-text-secondary\" />\n </button>\n {showMenu && (\n <div className=\"absolute right-0 mt-1 w-36 bg-bg-surface border border-border-default rounded-lg shadow-lg z-10\">\n {onActivate && vibe.status !== 'ACTIVE' && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onActivate(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg\"\n >\n <Play className=\"w-4 h-4\" />\n Activate\n </button>\n )}\n {onEdit && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onEdit(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Settings className=\"w-4 h-4\" />\n Edit\n </button>\n )}\n {onOpenInEditor && vibe.path && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onOpenInEditor(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <ExternalLink className=\"w-4 h-4\" />\n Open in VS Code\n </button>\n )}\n {onArchive && vibe.status !== 'ARCHIVED' && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onArchive(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-b-lg\"\n >\n <Archive className=\"w-4 h-4\" />\n Archive\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </td>\n </tr>\n );\n}\n\nexport function VibeList({\n vibes,\n onOpen,\n onEdit,\n onArchive,\n onActivate,\n onOpenInEditor,\n onCreateNew,\n isLoading,\n selectedVibeIds = new Set<string>(),\n onToggleSelect,\n onToggleAllVisible,\n allVisibleSelected = false,\n partiallySelected = false,\n}: VibeListProps) {\n const tr = useTr();\n\n if (!isLoading && vibes.length === 0) {\n return (\n <EmptyState\n icon={<FolderOpen className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibecontrols.vibes.list.emptyTitle', 'No vibes yet')}\n description={tr(\n 'vibecontrols.vibes.list.emptyDescription',\n 'Vibes are your development projects and environments. Create your first vibe to organize your work.'\n )}\n action={\n onCreateNew && (\n <button\n onClick={onCreateNew}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('vibecontrols.vibes.list.createVibe', 'Create Vibe')}\n </button>\n )\n }\n />\n );\n }\n\n return (\n <>\n {/* Mobile: Card view */}\n <div className=\"sm:hidden space-y-3\">\n {vibes.map((vibe) => (\n <VibeListCard\n key={vibe.id}\n vibe={vibe}\n onOpen={onOpen}\n onActivate={onActivate}\n onOpenInEditor={onOpenInEditor}\n onArchive={onArchive}\n selected={selectedVibeIds.has(vibe.id)}\n onToggleSelect={onToggleSelect ? (checked) => onToggleSelect(vibe, checked) : undefined}\n />\n ))}\n </div>\n\n {/* Desktop: Table view */}\n <div className=\"hidden sm:block border border-border-default rounded-lg overflow-visible\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"bg-bg-sunken border-b border-border-default\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider w-12\">\n {onToggleAllVisible ? (\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={onToggleAllVisible}\n ariaLabel=\"Select all visible vibes\"\n />\n ) : null}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Name\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Type\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Status\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Path\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Branch\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Tags\n </th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Actions\n </th>\n </tr>\n </thead>\n <tbody>\n {vibes.map((vibe) => (\n <VibeRow\n key={vibe.id}\n vibe={vibe}\n onOpen={onOpen}\n onEdit={onEdit}\n onArchive={onArchive}\n onActivate={onActivate}\n onOpenInEditor={onOpenInEditor}\n selected={selectedVibeIds.has(vibe.id)}\n onToggleSelect={\n onToggleSelect ? (checked) => onToggleSelect(vibe, checked) : undefined\n }\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"VibeList.js","names":[],"sources":["../../../src/components/vibes/VibeList.tsx"],"sourcesContent":["import type { Vibe } from './types';\nimport { vibeTypeIcons } from './icons';\nimport { StatusBadge } from '../shared/StatusBadge';\nimport { EmptyState } from '../shared/EmptyState';\nimport { SelectionCheckbox } from '../shared/SelectionCheckbox';\nimport {\n FolderOpen,\n Plus,\n GitBranch,\n Tag,\n MoreVertical,\n Play,\n Archive,\n Settings,\n ExternalLink,\n} from 'lucide-react';\nimport { useState } from 'react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface VibeListProps {\n vibes: Vibe[];\n onOpen?: (vibe: Vibe) => void;\n onEdit?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n onCreateNew?: () => void;\n isLoading?: boolean;\n selectedVibeIds?: Set<string>;\n onToggleSelect?: (vibe: Vibe, checked: boolean) => void;\n onToggleAllVisible?: (checked: boolean) => void;\n allVisibleSelected?: boolean;\n partiallySelected?: boolean;\n}\n\n/**\n * Mobile card view for a single vibe\n */\nfunction VibeListCard({\n vibe,\n onOpen,\n onActivate,\n onOpenInEditor,\n onArchive,\n selected,\n onToggleSelect,\n}: {\n vibe: Vibe;\n onOpen?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}) {\n const Icon = vibeTypeIcons[vibe.type] || FolderOpen;\n\n return (\n <div\n className=\"p-4 border border-border-default rounded-lg bg-bg-surface hover:bg-bg-sunken/50 cursor-pointer transition-colors\"\n onClick={() => onOpen?.(vibe)}\n >\n {/* Header: Icon, Name, Status */}\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3 min-w-0 flex-1\">\n {onToggleSelect && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={!!selected}\n onChange={onToggleSelect}\n ariaLabel={`Select vibe ${vibe.name}`}\n />\n </div>\n )}\n <Icon className=\"w-5 h-5 text-action-primary-bg flex-shrink-0 mt-0.5\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{vibe.name}</p>\n {vibe.description && (\n <p className=\"text-xs text-text-muted truncate mt-0.5\">{vibe.description}</p>\n )}\n </div>\n </div>\n <StatusBadge status={vibe.status} />\n </div>\n\n {/* Meta info row */}\n <div className=\"mt-3 flex flex-wrap items-center gap-x-4 gap-y-2 text-xs text-text-secondary\">\n {vibe.gitBranch && (\n <span className=\"flex items-center gap-1\">\n <GitBranch className=\"w-3 h-3\" />\n {vibe.gitBranch}\n </span>\n )}\n {vibe.tags && vibe.tags.length > 0 && (\n <span className=\"flex items-center gap-1\">\n <Tag className=\"w-3 h-3\" />\n {vibe.tags.length} tag{vibe.tags.length !== 1 ? 's' : ''}\n </span>\n )}\n </div>\n\n {/* Path (if exists) */}\n {vibe.path && (\n <div className=\"mt-2 text-xs font-mono text-text-muted truncate\">{vibe.path}</div>\n )}\n\n {/* Actions */}\n <div className=\"mt-3 flex items-center gap-2 justify-end border-t border-border-default pt-3\">\n {onActivate && vibe.status !== 'ACTIVE' && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onActivate(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Activate\"\n >\n <Play className=\"w-4 h-4 text-text-secondary\" />\n </button>\n )}\n {onOpenInEditor && vibe.path && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onOpenInEditor(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Open in VS Code\"\n >\n <ExternalLink className=\"w-4 h-4 text-text-secondary\" />\n </button>\n )}\n {onArchive && vibe.status !== 'ARCHIVED' && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onArchive(vibe);\n }}\n className=\"p-2 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Archive\"\n >\n <Archive className=\"w-4 h-4 text-text-secondary\" />\n </button>\n )}\n </div>\n </div>\n );\n}\n\nfunction VibeRow({\n vibe,\n onOpen,\n onEdit,\n onArchive,\n onActivate,\n onOpenInEditor,\n selected,\n onToggleSelect,\n}: {\n vibe: Vibe;\n onOpen?: (vibe: Vibe) => void;\n onEdit?: (vibe: Vibe) => void;\n onArchive?: (vibe: Vibe) => void;\n onActivate?: (vibe: Vibe) => void;\n onOpenInEditor?: (vibe: Vibe) => void;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}) {\n const [showMenu, setShowMenu] = useState(false);\n const Icon = vibeTypeIcons[vibe.type] || FolderOpen;\n\n return (\n <tr\n className={`border-b border-border-default hover:bg-bg-sunken/50 cursor-pointer transition-colors ${\n selected ? 'bg-bg-sunken/40' : ''\n }`}\n onClick={() => onOpen?.(vibe)}\n >\n <td className=\"px-4 py-3\">\n {onToggleSelect && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={!!selected}\n onChange={onToggleSelect}\n ariaLabel={`Select vibe ${vibe.name}`}\n />\n </div>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <Icon className=\"w-4 h-4 text-action-primary-bg shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{vibe.name}</p>\n {vibe.description && (\n <p className=\"text-xs text-text-muted truncate max-w-[250px]\">{vibe.description}</p>\n )}\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <StatusBadge status={vibe.status} />\n </td>\n <td className=\"px-4 py-3\">\n {vibe.path ? (\n <span className=\"text-xs font-mono text-text-muted truncate block max-w-[180px]\">\n {vibe.path}\n </span>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {vibe.gitBranch ? (\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <GitBranch className=\"w-3 h-3\" />\n <span className=\"truncate max-w-[100px]\">{vibe.gitBranch}</span>\n </div>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {vibe.tags && vibe.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {vibe.tags.slice(0, 2).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"w-2.5 h-2.5\" />\n {tag}\n </span>\n ))}\n {vibe.tags.length > 2 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{vibe.tags.length - 2}\n </span>\n )}\n </div>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1 justify-end\">\n {(onEdit || onArchive || onActivate || onOpenInEditor) && (\n <div className=\"relative\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n >\n <MoreVertical className=\"w-3.5 h-3.5 text-text-secondary\" />\n </button>\n {showMenu && (\n <div className=\"absolute right-0 mt-1 w-36 bg-bg-surface border border-border-default rounded-lg shadow-lg z-10\">\n {onActivate && vibe.status !== 'ACTIVE' && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onActivate(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg\"\n >\n <Play className=\"w-4 h-4\" />\n Activate\n </button>\n )}\n {onEdit && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onEdit(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Settings className=\"w-4 h-4\" />\n Edit\n </button>\n )}\n {onOpenInEditor && vibe.path && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onOpenInEditor(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <ExternalLink className=\"w-4 h-4\" />\n Open in VS Code\n </button>\n )}\n {onArchive && vibe.status !== 'ARCHIVED' && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onArchive(vibe);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-b-lg\"\n >\n <Archive className=\"w-4 h-4\" />\n Archive\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </td>\n </tr>\n );\n}\n\nexport function VibeList({\n vibes,\n onOpen,\n onEdit,\n onArchive,\n onActivate,\n onOpenInEditor,\n onCreateNew,\n isLoading,\n selectedVibeIds = new Set<string>(),\n onToggleSelect,\n onToggleAllVisible,\n allVisibleSelected = false,\n partiallySelected = false,\n}: VibeListProps) {\n const tr = useTr();\n\n if (!isLoading && vibes.length === 0) {\n return (\n <EmptyState\n icon={<FolderOpen className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibecontrols.vibes.list.emptyTitle', 'No vibes yet')}\n description={tr(\n 'vibecontrols.vibes.list.emptyDescription',\n 'Vibes are your development projects and environments. Create your first vibe to organize your work.'\n )}\n action={\n onCreateNew && (\n <button\n onClick={onCreateNew}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('vibecontrols.vibes.list.createVibe', 'Create Vibe')}\n </button>\n )\n }\n />\n );\n }\n\n return (\n <>\n {/* Mobile: Card view */}\n <div className=\"sm:hidden space-y-3\">\n {vibes.map((vibe) => (\n <VibeListCard\n key={vibe.id}\n vibe={vibe}\n onOpen={onOpen}\n onActivate={onActivate}\n onOpenInEditor={onOpenInEditor}\n onArchive={onArchive}\n selected={selectedVibeIds.has(vibe.id)}\n onToggleSelect={onToggleSelect ? (checked) => onToggleSelect(vibe, checked) : undefined}\n />\n ))}\n </div>\n\n {/* Desktop: Table view */}\n <div className=\"hidden sm:block border border-border-default rounded-lg overflow-visible\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"bg-bg-sunken border-b border-border-default\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider w-12\">\n {onToggleAllVisible ? (\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={onToggleAllVisible}\n ariaLabel=\"Select all visible vibes\"\n />\n ) : null}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Name\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Status\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Path\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Branch\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Tags\n </th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Actions\n </th>\n </tr>\n </thead>\n <tbody>\n {vibes.map((vibe) => (\n <VibeRow\n key={vibe.id}\n vibe={vibe}\n onOpen={onOpen}\n onEdit={onEdit}\n onArchive={onArchive}\n onActivate={onActivate}\n onOpenInEditor={onOpenInEditor}\n selected={selectedVibeIds.has(vibe.id)}\n onToggleSelect={\n onToggleSelect ? (checked) => onToggleSelect(vibe, checked) : undefined\n }\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </>\n );\n}\n"],"mappings":"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"}