@burdenoff/microfe-vibecontrols 2026.601.6 → 2026.601.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/components/sessions/EntityInfoPopover.js +183 -0
  2. package/dist/components/sessions/EntityInfoPopover.js.map +1 -0
  3. package/dist/components/sessions/SessionCard.js +80 -72
  4. package/dist/components/sessions/SessionCard.js.map +1 -1
  5. package/dist/components/sessions/SessionGroup.js +49 -0
  6. package/dist/components/sessions/SessionGroup.js.map +1 -0
  7. package/dist/components/sessions/SessionInfoPanel.js +128 -0
  8. package/dist/components/sessions/SessionInfoPanel.js.map +1 -0
  9. package/dist/components/sessions/SessionList.js +109 -96
  10. package/dist/components/sessions/SessionList.js.map +1 -1
  11. package/dist/components/sessions/SessionsCommandPalette.js +36 -0
  12. package/dist/components/sessions/SessionsCommandPalette.js.map +1 -0
  13. package/dist/components/sessions/ShortcutCheatsheet.js +73 -0
  14. package/dist/components/sessions/ShortcutCheatsheet.js.map +1 -0
  15. package/dist/components/sessions/TerminalPanel.js +640 -537
  16. package/dist/components/sessions/TerminalPanel.js.map +1 -1
  17. package/dist/components/sessions/groupSessions.js +46 -0
  18. package/dist/components/sessions/groupSessions.js.map +1 -0
  19. package/dist/components/sessions/index.js +7 -0
  20. package/dist/components/sessions/sessionShortcuts.js +149 -0
  21. package/dist/components/sessions/sessionShortcuts.js.map +1 -0
  22. package/dist/components/shared/FilterDropdown.js +14 -13
  23. package/dist/components/shared/FilterDropdown.js.map +1 -1
  24. package/dist/components/shared/LinkToVibePanel.js.map +1 -1
  25. package/dist/components/vibe/VibeLinkedEntitiesPanel.js.map +1 -1
  26. package/dist/generated/wspace-operations.js +21 -0
  27. package/dist/generated/wspace-operations.js.map +1 -1
  28. package/dist/pages/SessionsPage.js +1189 -920
  29. package/dist/pages/SessionsPage.js.map +1 -1
  30. package/dist/pages/ai/AgentManagerPage.js.map +1 -1
  31. package/dist/store/vibeControlsStore.js +16 -1
  32. package/dist/store/vibeControlsStore.js.map +1 -1
  33. package/dist/translations/en.js +97 -2
  34. package/dist/translations/en.js.map +1 -1
  35. package/package.json +1 -1
@@ -0,0 +1,128 @@
1
+ import { useTr as e } from "../../shared/hooks/useTr.js";
2
+ import { useVibeNavigate as t } from "../../providers/VibeControlsProvider.js";
3
+ import { getAgentStatus as n } from "../agents/agentStatus.js";
4
+ import { Boxes as r, ExternalLink as i, MonitorSmartphone as a, Server as o, Terminal as s } from "lucide-react";
5
+ import { Fragment as c, jsx as l, jsxs as u } from "react/jsx-runtime";
6
+ import { Sheet as d, SheetContent as f, SheetDescription as p, SheetHeader as m, SheetTitle as h } from "@burdenoff/fe-libs/ui";
7
+ //#region src/components/sessions/SessionInfoPanel.tsx
8
+ function g({ label: e, value: t }) {
9
+ return /* @__PURE__ */ u("div", {
10
+ className: "flex items-center justify-between gap-3 py-1 text-sm",
11
+ children: [/* @__PURE__ */ l("span", {
12
+ className: "text-text-tertiary",
13
+ children: e
14
+ }), /* @__PURE__ */ l("span", {
15
+ className: "font-medium text-text-primary truncate max-w-[60%]",
16
+ title: t,
17
+ children: t
18
+ })]
19
+ });
20
+ }
21
+ function _({ open: _, onOpenChange: v, session: y }) {
22
+ let b = e(), x = t(), S = y?.agent, C = S?.target, w = y?.vibe;
23
+ return /* @__PURE__ */ l(d, {
24
+ open: _,
25
+ onOpenChange: v,
26
+ children: /* @__PURE__ */ u(f, {
27
+ side: "right",
28
+ className: "w-full sm:max-w-md overflow-y-auto",
29
+ "data-testid": "session-info-panel",
30
+ children: [/* @__PURE__ */ u(m, { children: [/* @__PURE__ */ u(h, {
31
+ className: "flex items-center gap-2",
32
+ children: [/* @__PURE__ */ l(s, { className: "size-4 text-text-secondary" }), y?.name ?? b("sessions.info.panelTitle", "Session details")]
33
+ }), /* @__PURE__ */ l(p, { children: b("sessions.info.panelDesc", "Where this session runs and how to reach it.") })] }), /* @__PURE__ */ l("div", {
34
+ className: "px-4 pb-4 space-y-5",
35
+ children: y ? /* @__PURE__ */ u(c, { children: [
36
+ /* @__PURE__ */ u("section", { children: [
37
+ /* @__PURE__ */ u("h3", {
38
+ className: "flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wider text-text-tertiary mb-2",
39
+ children: [/* @__PURE__ */ l(s, { className: "size-3.5" }), b("sessions.info.session", "Session")]
40
+ }),
41
+ /* @__PURE__ */ l(g, {
42
+ label: b("sessions.info.type", "Type"),
43
+ value: y.type
44
+ }),
45
+ /* @__PURE__ */ l(g, {
46
+ label: b("sessions.info.status", "Status"),
47
+ value: y.status
48
+ }),
49
+ y.workingDirectory && /* @__PURE__ */ l(g, {
50
+ label: b("sessions.info.cwd", "Working dir"),
51
+ value: y.workingDirectory
52
+ })
53
+ ] }),
54
+ S && /* @__PURE__ */ u("section", { children: [
55
+ /* @__PURE__ */ u("h3", {
56
+ className: "flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wider text-text-tertiary mb-2",
57
+ children: [/* @__PURE__ */ l(o, { className: "size-3.5" }), b("sessions.info.agent", "Agent")]
58
+ }),
59
+ /* @__PURE__ */ l(g, {
60
+ label: b("sessions.info.name", "Name"),
61
+ value: S.name
62
+ }),
63
+ /* @__PURE__ */ l(g, {
64
+ label: b("sessions.info.status", "Status"),
65
+ value: n(S)
66
+ }),
67
+ S.hostname && /* @__PURE__ */ l(g, {
68
+ label: b("sessions.info.host", "Host"),
69
+ value: S.hostname
70
+ }),
71
+ S.platform && /* @__PURE__ */ l(g, {
72
+ label: b("sessions.info.platform", "Platform"),
73
+ value: S.platform
74
+ }),
75
+ /* @__PURE__ */ u("button", {
76
+ type: "button",
77
+ onClick: () => x(`/agents/${S.id}`),
78
+ className: "mt-2 inline-flex items-center gap-1.5 text-xs font-medium text-text-link hover:underline",
79
+ children: [/* @__PURE__ */ l(i, { className: "size-3" }), b("sessions.info.viewAgent", "View agent")]
80
+ })
81
+ ] }),
82
+ C && /* @__PURE__ */ u("section", { children: [
83
+ /* @__PURE__ */ u("h3", {
84
+ className: "flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wider text-text-tertiary mb-2",
85
+ children: [/* @__PURE__ */ l(a, { className: "size-3.5" }), b("sessions.info.target", "Target")]
86
+ }),
87
+ /* @__PURE__ */ l(g, {
88
+ label: b("sessions.info.name", "Name"),
89
+ value: C.name
90
+ }),
91
+ /* @__PURE__ */ l(g, {
92
+ label: b("sessions.info.type", "Type"),
93
+ value: C.type
94
+ }),
95
+ /* @__PURE__ */ l(g, {
96
+ label: b("sessions.info.status", "Status"),
97
+ value: C.status
98
+ }),
99
+ C.host && /* @__PURE__ */ l(g, {
100
+ label: b("sessions.info.address", "Address"),
101
+ value: `${C.host}${C.port ? `:${C.port}` : ""}`
102
+ }),
103
+ /* @__PURE__ */ u("button", {
104
+ type: "button",
105
+ onClick: () => x(`/targets/${C.id}`),
106
+ className: "mt-2 inline-flex items-center gap-1.5 text-xs font-medium text-text-link hover:underline",
107
+ children: [/* @__PURE__ */ l(i, { className: "size-3" }), b("sessions.info.viewTarget", "View target")]
108
+ })
109
+ ] }),
110
+ w && /* @__PURE__ */ u("section", { children: [/* @__PURE__ */ u("h3", {
111
+ className: "flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wider text-text-tertiary mb-2",
112
+ children: [/* @__PURE__ */ l(r, { className: "size-3.5" }), b("sessions.info.vibe", "Vibe")]
113
+ }), /* @__PURE__ */ l(g, {
114
+ label: b("sessions.info.name", "Name"),
115
+ value: w.name
116
+ })] })
117
+ ] }) : /* @__PURE__ */ l("p", {
118
+ className: "text-sm text-text-tertiary",
119
+ children: b("sessions.info.noActive", "No active terminal session.")
120
+ })
121
+ })]
122
+ })
123
+ });
124
+ }
125
+ //#endregion
126
+ export { _ as SessionInfoPanel };
127
+
128
+ //# sourceMappingURL=SessionInfoPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionInfoPanel.js","names":[],"sources":["../../../src/components/sessions/SessionInfoPanel.tsx"],"sourcesContent":["/**\n * SessionInfoPanel — a side sheet summarising the active terminal tab's\n * session: which agent it runs on, which target machine that agent is\n * installed on, and the optional vibe. Each entity links to its full\n * detail page. Opened from the terminal status bar or the `i` shortcut.\n */\nimport {\n Sheet,\n SheetContent,\n SheetHeader,\n SheetTitle,\n SheetDescription,\n} from '@burdenoff/fe-libs/ui';\nimport { Server, MonitorSmartphone, Boxes, ExternalLink, Terminal } from 'lucide-react';\nimport { getAgentStatus } from '@/components/agents/agentStatus';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useTr } from '../../shared/hooks/useTr';\nimport type { Session } from './types';\n\nfunction Field({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"flex items-center justify-between gap-3 py-1 text-sm\">\n <span className=\"text-text-tertiary\">{label}</span>\n <span className=\"font-medium text-text-primary truncate max-w-[60%]\" title={value}>\n {value}\n </span>\n </div>\n );\n}\n\nexport interface SessionInfoPanelProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n session: Session | null;\n}\n\nexport function SessionInfoPanel({ open, onOpenChange, session }: SessionInfoPanelProps) {\n const tr = useTr();\n const navigate = useVibeNavigate();\n const agent = session?.agent;\n const target = agent?.target;\n const vibe = session?.vibe;\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent\n side=\"right\"\n className=\"w-full sm:max-w-md overflow-y-auto\"\n data-testid=\"session-info-panel\"\n >\n <SheetHeader>\n <SheetTitle className=\"flex items-center gap-2\">\n <Terminal className=\"size-4 text-text-secondary\" />\n {session?.name ?? tr('sessions.info.panelTitle', 'Session details')}\n </SheetTitle>\n <SheetDescription>\n {tr('sessions.info.panelDesc', 'Where this session runs and how to reach it.')}\n </SheetDescription>\n </SheetHeader>\n\n <div className=\"px-4 pb-4 space-y-5\">\n {!session ? (\n <p className=\"text-sm text-text-tertiary\">\n {tr('sessions.info.noActive', 'No active terminal session.')}\n </p>\n ) : (\n <>\n <section>\n <h3 className=\"flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wider text-text-tertiary mb-2\">\n <Terminal className=\"size-3.5\" />\n {tr('sessions.info.session', 'Session')}\n </h3>\n <Field label={tr('sessions.info.type', 'Type')} value={session.type} />\n <Field label={tr('sessions.info.status', 'Status')} value={session.status} />\n {session.workingDirectory && (\n <Field\n label={tr('sessions.info.cwd', 'Working dir')}\n value={session.workingDirectory}\n />\n )}\n </section>\n\n {agent && (\n <section>\n <h3 className=\"flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wider text-text-tertiary mb-2\">\n <Server className=\"size-3.5\" />\n {tr('sessions.info.agent', 'Agent')}\n </h3>\n <Field label={tr('sessions.info.name', 'Name')} value={agent.name} />\n <Field\n label={tr('sessions.info.status', 'Status')}\n value={getAgentStatus(agent)}\n />\n {agent.hostname && (\n <Field label={tr('sessions.info.host', 'Host')} value={agent.hostname} />\n )}\n {agent.platform && (\n <Field\n label={tr('sessions.info.platform', 'Platform')}\n value={agent.platform}\n />\n )}\n <button\n type=\"button\"\n onClick={() => navigate(`/agents/${agent.id}`)}\n className=\"mt-2 inline-flex items-center gap-1.5 text-xs font-medium text-text-link hover:underline\"\n >\n <ExternalLink className=\"size-3\" />\n {tr('sessions.info.viewAgent', 'View agent')}\n </button>\n </section>\n )}\n\n {target && (\n <section>\n <h3 className=\"flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wider text-text-tertiary mb-2\">\n <MonitorSmartphone className=\"size-3.5\" />\n {tr('sessions.info.target', 'Target')}\n </h3>\n <Field label={tr('sessions.info.name', 'Name')} value={target.name} />\n <Field label={tr('sessions.info.type', 'Type')} value={target.type} />\n <Field label={tr('sessions.info.status', 'Status')} value={target.status} />\n {target.host && (\n <Field\n label={tr('sessions.info.address', 'Address')}\n value={`${target.host}${target.port ? `:${target.port}` : ''}`}\n />\n )}\n <button\n type=\"button\"\n onClick={() => navigate(`/targets/${target.id}`)}\n className=\"mt-2 inline-flex items-center gap-1.5 text-xs font-medium text-text-link hover:underline\"\n >\n <ExternalLink className=\"size-3\" />\n {tr('sessions.info.viewTarget', 'View target')}\n </button>\n </section>\n )}\n\n {vibe && (\n <section>\n <h3 className=\"flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wider text-text-tertiary mb-2\">\n <Boxes className=\"size-3.5\" />\n {tr('sessions.info.vibe', 'Vibe')}\n </h3>\n <Field label={tr('sessions.info.name', 'Name')} value={vibe.name} />\n </section>\n )}\n </>\n )}\n </div>\n </SheetContent>\n </Sheet>\n );\n}\n"],"mappings":"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"}
@@ -1,162 +1,170 @@
1
1
  import { useTr as e } from "../../shared/hooks/useTr.js";
2
2
  import { EmptyState as t } from "../shared/EmptyState.js";
3
3
  import { SessionStatusBadge as n } from "./SessionStatusBadge.js";
4
- import { useState as r } from "react";
5
- import { Clock as i, MoreVertical as a, Play as o, Plus as s, RotateCcw as c, Share2 as l, Square as u, Terminal as d } from "lucide-react";
6
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
4
+ import { AgentInfoPopover as r, TargetInfoPopover as i } from "./EntityInfoPopover.js";
5
+ import { useState as a } from "react";
6
+ import { Clock as o, MoreVertical as s, Play as c, Plus as l, RotateCcw as u, Share2 as d, Square as f, Terminal as p } from "lucide-react";
7
+ import { jsx as m, jsxs as h } from "react/jsx-runtime";
7
8
  //#region src/components/sessions/SessionList.tsx
8
- var m = {
9
+ var g = {
9
10
  TMUX: "🖥️",
10
11
  SSH: "🔐",
11
12
  TERMINAL: "💻",
12
13
  SCRIPT: "📜",
13
14
  CUSTOM: "⚙️"
14
15
  };
15
- function h({ session: t, onOpen: s, onStart: h, onStop: g, onRestart: _, onTerminate: v, onOpenTerminal: y, onShare: b, selected: x, onToggleSelect: S }) {
16
- let C = e(), [w, T] = r(!1), E = t.status === "RUNNING", D = t.status === "STOPPED" || t.status === "TERMINATED";
17
- return /* @__PURE__ */ p("tr", {
18
- className: `border-b border-border-subtle hover:bg-bg-sunken/50 cursor-pointer transition-colors ${x ? "bg-action-primary-bg/5" : ""}`,
19
- onClick: () => s?.(t),
16
+ function _({ session: t, onOpen: l, onStart: _, onStop: v, onRestart: y, onTerminate: b, onOpenTerminal: x, onShare: S, selected: C, onToggleSelect: w }) {
17
+ let T = e(), [E, D] = a(!1), O = t.status === "RUNNING", k = t.status === "STOPPED" || t.status === "TERMINATED";
18
+ return /* @__PURE__ */ h("tr", {
19
+ className: `border-b border-border-subtle hover:bg-bg-sunken/50 cursor-pointer transition-colors ${C ? "bg-action-primary-bg/5" : ""}`,
20
+ onClick: () => l?.(t),
20
21
  children: [
21
- S && /* @__PURE__ */ f("td", {
22
+ w && /* @__PURE__ */ m("td", {
22
23
  className: "p-3 w-10",
23
- children: /* @__PURE__ */ f("input", {
24
+ children: /* @__PURE__ */ m("input", {
24
25
  "aria-label": "control",
25
26
  type: "checkbox",
26
- checked: x ?? !1,
27
+ checked: C ?? !1,
27
28
  onChange: (e) => {
28
- e.stopPropagation(), S();
29
+ e.stopPropagation(), w();
29
30
  },
30
31
  onClick: (e) => e.stopPropagation(),
31
32
  className: "size-4 rounded border-border-default text-action-primary-bg focus:ring-action-primary-bg"
32
33
  })
33
34
  }),
34
- /* @__PURE__ */ f("td", {
35
+ /* @__PURE__ */ m("td", {
35
36
  className: "px-4 py-3",
36
- children: /* @__PURE__ */ p("div", {
37
+ children: /* @__PURE__ */ h("div", {
37
38
  className: "flex items-center gap-3 min-w-0",
38
- children: [/* @__PURE__ */ f(d, { className: "size-4 text-text-secondary shrink-0" }), /* @__PURE__ */ p("div", {
39
+ children: [/* @__PURE__ */ m(p, { className: "size-4 text-text-secondary shrink-0" }), /* @__PURE__ */ h("div", {
39
40
  className: "min-w-0",
40
- children: [/* @__PURE__ */ f("p", {
41
+ children: [/* @__PURE__ */ m("p", {
41
42
  className: "text-sm font-medium text-text-primary truncate",
42
43
  children: t.name
43
- }), t.command && /* @__PURE__ */ p("p", {
44
+ }), t.command && /* @__PURE__ */ h("p", {
44
45
  className: "text-xs font-mono text-text-muted truncate max-w-[200px]",
45
46
  children: ["$ ", t.command]
46
47
  })]
47
48
  })]
48
49
  })
49
50
  }),
50
- /* @__PURE__ */ f("td", {
51
+ /* @__PURE__ */ m("td", {
51
52
  className: "px-4 py-3",
52
- children: /* @__PURE__ */ p("div", {
53
+ children: /* @__PURE__ */ h("div", {
53
54
  className: "flex items-center gap-1.5",
54
- children: [/* @__PURE__ */ f("span", {
55
+ children: [/* @__PURE__ */ m("span", {
55
56
  className: "text-sm",
56
- children: m[t.type] || "💻"
57
- }), /* @__PURE__ */ f("span", {
57
+ children: g[t.type] || "💻"
58
+ }), /* @__PURE__ */ m("span", {
58
59
  className: "text-sm text-text-secondary",
59
60
  children: t.type
60
61
  })]
61
62
  })
62
63
  }),
63
- /* @__PURE__ */ f("td", {
64
+ /* @__PURE__ */ m("td", {
64
65
  className: "px-4 py-3",
65
- children: /* @__PURE__ */ f(n, { status: t.status })
66
+ children: /* @__PURE__ */ m(n, { status: t.status })
66
67
  }),
67
- /* @__PURE__ */ f("td", {
68
+ /* @__PURE__ */ m("td", {
68
69
  className: "px-4 py-3",
69
- children: /* @__PURE__ */ f("span", {
70
- className: "text-sm text-text-secondary truncate block max-w-[120px]",
71
- children: t.agent?.name || "-"
70
+ children: t.agent ? /* @__PURE__ */ m(r, { agent: t.agent }) : /* @__PURE__ */ m("span", {
71
+ className: "text-sm text-text-secondary",
72
+ children: "-"
72
73
  })
73
74
  }),
74
- /* @__PURE__ */ f("td", {
75
+ /* @__PURE__ */ m("td", {
75
76
  className: "px-4 py-3",
76
- children: /* @__PURE__ */ f("span", {
77
+ children: t.agent?.target ? /* @__PURE__ */ m(i, { target: t.agent.target }) : /* @__PURE__ */ m("span", {
78
+ className: "text-sm text-text-secondary",
79
+ children: "-"
80
+ })
81
+ }),
82
+ /* @__PURE__ */ m("td", {
83
+ className: "px-4 py-3",
84
+ children: /* @__PURE__ */ m("span", {
77
85
  className: "text-sm text-text-secondary truncate block max-w-[120px]",
78
86
  children: t.vibe?.name || "-"
79
87
  })
80
88
  }),
81
- /* @__PURE__ */ f("td", {
89
+ /* @__PURE__ */ m("td", {
82
90
  className: "px-4 py-3",
83
- children: /* @__PURE__ */ p("div", {
91
+ children: /* @__PURE__ */ h("div", {
84
92
  className: "flex items-center gap-1.5 text-xs text-text-muted",
85
- children: [/* @__PURE__ */ f(i, { className: "size-3" }), ((e) => {
93
+ children: [/* @__PURE__ */ m(o, { className: "size-3" }), ((e) => {
86
94
  if (!e) return "Never";
87
95
  let t = Date.now() - new Date(e).getTime();
88
96
  return t < 6e4 ? "Just now" : t < 36e5 ? `${Math.floor(t / 6e4)}m ago` : t < 864e5 ? `${Math.floor(t / 36e5)}h ago` : new Date(e).toLocaleDateString();
89
97
  })(t.updatedAt)]
90
98
  })
91
99
  }),
92
- /* @__PURE__ */ f("td", {
100
+ /* @__PURE__ */ m("td", {
93
101
  className: "px-4 py-3",
94
- children: /* @__PURE__ */ p("div", {
102
+ children: /* @__PURE__ */ h("div", {
95
103
  className: "flex items-center gap-1 justify-end",
96
104
  children: [
97
- D && h && /* @__PURE__ */ f("button", {
105
+ k && _ && /* @__PURE__ */ m("button", {
98
106
  type: "button",
99
107
  onClick: (e) => {
100
- e.stopPropagation(), h(t);
108
+ e.stopPropagation(), _(t);
101
109
  },
102
110
  className: "p-1.5 rounded hover:bg-bg-sunken transition-colors",
103
111
  title: "Start",
104
- children: /* @__PURE__ */ f(o, { className: "size-3.5 text-text-secondary" })
112
+ children: /* @__PURE__ */ m(c, { className: "size-3.5 text-text-secondary" })
105
113
  }),
106
- E && g && /* @__PURE__ */ f("button", {
114
+ O && v && /* @__PURE__ */ m("button", {
107
115
  type: "button",
108
116
  onClick: (e) => {
109
- e.stopPropagation(), g(t);
117
+ e.stopPropagation(), v(t);
110
118
  },
111
119
  className: "p-1.5 rounded hover:bg-bg-sunken transition-colors",
112
120
  title: "Stop",
113
- children: /* @__PURE__ */ f(u, { className: "size-3.5 text-text-secondary" })
121
+ children: /* @__PURE__ */ m(f, { className: "size-3.5 text-text-secondary" })
114
122
  }),
115
- E && _ && /* @__PURE__ */ f("button", {
123
+ O && y && /* @__PURE__ */ m("button", {
116
124
  type: "button",
117
125
  onClick: (e) => {
118
- e.stopPropagation(), _(t);
126
+ e.stopPropagation(), y(t);
119
127
  },
120
128
  className: "p-1.5 rounded hover:bg-bg-sunken transition-colors",
121
129
  title: "Restart",
122
- children: /* @__PURE__ */ f(c, { className: "size-3.5 text-text-secondary" })
130
+ children: /* @__PURE__ */ m(u, { className: "size-3.5 text-text-secondary" })
123
131
  }),
124
- E && y && /* @__PURE__ */ f("button", {
132
+ O && x && /* @__PURE__ */ m("button", {
125
133
  type: "button",
126
134
  onClick: (e) => {
127
- e.stopPropagation(), y(t);
135
+ e.stopPropagation(), x(t);
128
136
  },
129
137
  className: "p-1.5 rounded hover:bg-bg-sunken transition-colors",
130
138
  title: "Open Terminal",
131
- children: /* @__PURE__ */ f(d, { className: "size-3.5 text-text-secondary" })
139
+ children: /* @__PURE__ */ m(p, { className: "size-3.5 text-text-secondary" })
132
140
  }),
133
- E && b && /* @__PURE__ */ f("button", {
141
+ O && S && /* @__PURE__ */ m("button", {
134
142
  type: "button",
135
143
  onClick: (e) => {
136
- e.stopPropagation(), b(t);
144
+ e.stopPropagation(), S(t);
137
145
  },
138
146
  className: "p-1.5 rounded hover:bg-bg-sunken transition-colors",
139
147
  title: "Share Session",
140
- children: /* @__PURE__ */ f(l, { className: "size-3.5 text-text-secondary" })
148
+ children: /* @__PURE__ */ m(d, { className: "size-3.5 text-text-secondary" })
141
149
  }),
142
- v && /* @__PURE__ */ p("div", {
150
+ b && /* @__PURE__ */ h("div", {
143
151
  className: "relative",
144
- children: [/* @__PURE__ */ f("button", {
152
+ children: [/* @__PURE__ */ m("button", {
145
153
  type: "button",
146
154
  onClick: (e) => {
147
- e.stopPropagation(), T(!w);
155
+ e.stopPropagation(), D(!E);
148
156
  },
149
157
  className: "p-1.5 rounded hover:bg-bg-sunken transition-colors",
150
- children: /* @__PURE__ */ f(a, { className: "size-3.5 text-text-secondary" })
151
- }), w && /* @__PURE__ */ f("div", {
158
+ children: /* @__PURE__ */ m(s, { className: "size-3.5 text-text-secondary" })
159
+ }), E && /* @__PURE__ */ m("div", {
152
160
  className: "absolute right-0 mt-1 w-36 bg-bg-surface border border-border-default rounded-lg shadow-lg z-10",
153
- children: v && /* @__PURE__ */ f("button", {
161
+ children: b && /* @__PURE__ */ m("button", {
154
162
  type: "button",
155
163
  onClick: (e) => {
156
- e.stopPropagation(), v(t), T(!1);
164
+ e.stopPropagation(), b(t), D(!1);
157
165
  },
158
166
  className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-lg",
159
- children: C("vibecontrols.sessions.list.terminate", "Terminate")
167
+ children: T("vibecontrols.sessions.list.terminate", "Terminate")
160
168
  })
161
169
  })]
162
170
  })
@@ -166,79 +174,84 @@ function h({ session: t, onOpen: s, onStart: h, onStop: g, onRestart: _, onTermi
166
174
  ]
167
175
  });
168
176
  }
169
- function g({ sessions: n, onOpen: r, onStart: i, onStop: a, onRestart: o, onTerminate: c, onOpenTerminal: l, onShare: u, onCreateNew: m, isLoading: g, selectedIds: _, onToggleSelect: v, onSelectAll: y, onDeselectAll: b }) {
170
- let x = e(), S = _ && n.length > 0 && _.size === n.length;
171
- return !g && n.length === 0 ? /* @__PURE__ */ f(t, {
172
- icon: /* @__PURE__ */ f(d, { className: "size-8 text-text-secondary" }),
173
- title: x("vibecontrols.sessions.list.noSessionsTitle", "No sessions yet"),
174
- description: x("vibecontrols.sessions.list.noSessionsDescription", "Sessions are terminal processes running on your agents. Start a session to run commands, scripts, or interactive shells."),
175
- action: m && /* @__PURE__ */ p("button", {
177
+ function v({ sessions: n, onOpen: r, onStart: i, onStop: a, onRestart: o, onTerminate: s, onOpenTerminal: c, onShare: u, onCreateNew: d, isLoading: f, selectedIds: g, onToggleSelect: v, onSelectAll: y, onDeselectAll: b, hideHeaderSelectAll: x = !1 }) {
178
+ let S = e(), C = g && n.length > 0 && g.size === n.length;
179
+ return !f && n.length === 0 ? /* @__PURE__ */ m(t, {
180
+ icon: /* @__PURE__ */ m(p, { className: "size-8 text-text-secondary" }),
181
+ title: S("vibecontrols.sessions.list.noSessionsTitle", "No sessions yet"),
182
+ description: S("vibecontrols.sessions.list.noSessionsDescription", "Sessions are terminal processes running on your agents. Start a session to run commands, scripts, or interactive shells."),
183
+ action: d && /* @__PURE__ */ h("button", {
176
184
  type: "button",
177
- onClick: m,
185
+ onClick: d,
178
186
  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",
179
- children: [/* @__PURE__ */ f(s, { className: "size-4" }), x("vibecontrols.sessions.list.startSession", "Start Session")]
187
+ children: [/* @__PURE__ */ m(l, { className: "size-4" }), S("vibecontrols.sessions.list.startSession", "Start Session")]
180
188
  })
181
- }) : /* @__PURE__ */ f("div", {
189
+ }) : /* @__PURE__ */ m("div", {
182
190
  className: "border border-border-default rounded-lg overflow-visible",
183
- children: /* @__PURE__ */ f("div", {
191
+ children: /* @__PURE__ */ m("div", {
184
192
  className: "overflow-x-auto",
185
- children: /* @__PURE__ */ p("table", {
193
+ children: /* @__PURE__ */ h("table", {
186
194
  className: "w-full",
187
- children: [/* @__PURE__ */ f("thead", { children: /* @__PURE__ */ p("tr", {
195
+ children: [/* @__PURE__ */ m("thead", { children: /* @__PURE__ */ h("tr", {
188
196
  className: "bg-bg-sunken border-b border-border-default",
189
197
  children: [
190
- v && /* @__PURE__ */ f("th", {
198
+ v && x && /* @__PURE__ */ m("th", { className: "px-3 py-2.5 w-10" }),
199
+ v && !x && /* @__PURE__ */ m("th", {
191
200
  className: "px-3 py-2.5 w-10",
192
- children: /* @__PURE__ */ f("input", {
201
+ children: /* @__PURE__ */ m("input", {
193
202
  "aria-label": "control",
194
203
  type: "checkbox",
195
- checked: S ?? !1,
204
+ checked: C ?? !1,
196
205
  onChange: () => {
197
- S && b ? b() : y && y();
206
+ C && b ? b() : y && y();
198
207
  },
199
208
  className: "size-4 rounded border-border-default text-action-primary-bg focus:ring-action-primary-bg",
200
- title: S ? "Deselect all" : "Select all"
209
+ title: C ? "Deselect all" : "Select all"
201
210
  })
202
211
  }),
203
- /* @__PURE__ */ f("th", {
212
+ /* @__PURE__ */ m("th", {
213
+ className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
214
+ children: S("vibecontrols.sessions.list.colName", "Name")
215
+ }),
216
+ /* @__PURE__ */ m("th", {
204
217
  className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
205
- children: x("vibecontrols.sessions.list.colName", "Name")
218
+ children: S("vibecontrols.sessions.list.colType", "Type")
206
219
  }),
207
- /* @__PURE__ */ f("th", {
220
+ /* @__PURE__ */ m("th", {
208
221
  className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
209
- children: x("vibecontrols.sessions.list.colType", "Type")
222
+ children: S("vibecontrols.sessions.list.colStatus", "Status")
210
223
  }),
211
- /* @__PURE__ */ f("th", {
224
+ /* @__PURE__ */ m("th", {
212
225
  className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
213
- children: x("vibecontrols.sessions.list.colStatus", "Status")
226
+ children: S("vibecontrols.sessions.list.colAgent", "Agent")
214
227
  }),
215
- /* @__PURE__ */ f("th", {
228
+ /* @__PURE__ */ m("th", {
216
229
  className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
217
- children: x("vibecontrols.sessions.list.colAgent", "Agent")
230
+ children: S("vibecontrols.sessions.list.colTarget", "Target")
218
231
  }),
219
- /* @__PURE__ */ f("th", {
232
+ /* @__PURE__ */ m("th", {
220
233
  className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
221
- children: x("vibecontrols.sessions.list.colVibe", "Vibe")
234
+ children: S("vibecontrols.sessions.list.colVibe", "Vibe")
222
235
  }),
223
- /* @__PURE__ */ f("th", {
236
+ /* @__PURE__ */ m("th", {
224
237
  className: "px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider",
225
- children: x("vibecontrols.sessions.list.colUpdated", "Updated")
238
+ children: S("vibecontrols.sessions.list.colUpdated", "Updated")
226
239
  }),
227
- /* @__PURE__ */ f("th", {
240
+ /* @__PURE__ */ m("th", {
228
241
  className: "px-4 py-2.5 text-right text-xs font-medium text-text-secondary uppercase tracking-wider",
229
- children: x("vibecontrols.sessions.list.colActions", "Actions")
242
+ children: S("vibecontrols.sessions.list.colActions", "Actions")
230
243
  })
231
244
  ]
232
- }) }), /* @__PURE__ */ f("tbody", { children: n.map((e) => /* @__PURE__ */ f(h, {
245
+ }) }), /* @__PURE__ */ m("tbody", { children: n.map((e) => /* @__PURE__ */ m(_, {
233
246
  session: e,
234
247
  onOpen: r,
235
248
  onStart: i,
236
249
  onStop: a,
237
250
  onRestart: o,
238
- onTerminate: c,
239
- onOpenTerminal: l,
251
+ onTerminate: s,
252
+ onOpenTerminal: c,
240
253
  onShare: u,
241
- selected: _?.has(e.id),
254
+ selected: g?.has(e.id),
242
255
  onToggleSelect: v ? () => v(e.id) : void 0
243
256
  }, e.id)) })]
244
257
  })
@@ -246,6 +259,6 @@ function g({ sessions: n, onOpen: r, onStart: i, onStop: a, onRestart: o, onTerm
246
259
  });
247
260
  }
248
261
  //#endregion
249
- export { g as SessionList };
262
+ export { v as SessionList };
250
263
 
251
264
  //# sourceMappingURL=SessionList.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SessionList.js","names":[],"sources":["../../../src/components/sessions/SessionList.tsx"],"sourcesContent":["import type { Session } from './types';\nimport { SessionStatusBadge } from './SessionStatusBadge';\nimport { EmptyState } from '../shared/EmptyState';\nimport { Terminal, Plus, Play, Square, RotateCcw, MoreVertical, Clock, Share2 } from 'lucide-react';\nimport { useState } from 'react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface SessionListProps {\n sessions: Session[];\n onOpen?: (session: Session) => void;\n onStart?: (session: Session) => void;\n onStop?: (session: Session) => void;\n onRestart?: (session: Session) => void;\n onTerminate?: (session: Session) => void;\n onOpenTerminal?: (session: Session) => void;\n onShare?: (session: Session) => void;\n onCreateNew?: () => void;\n isLoading?: boolean;\n /** Set of selected session IDs for bulk operations */\n selectedIds?: Set<string>;\n /** Toggle selection for a single session */\n onToggleSelect?: (sessionId: string) => void;\n /** Select all visible sessions */\n onSelectAll?: () => void;\n /** Deselect all sessions */\n onDeselectAll?: () => void;\n}\n\nconst sessionTypeIcons: Record<string, string> = {\n TMUX: '🖥️',\n SSH: '🔐',\n TERMINAL: '💻',\n SCRIPT: '📜',\n CUSTOM: '⚙️',\n};\n\nfunction SessionRow({\n session,\n onOpen,\n onStart,\n onStop,\n onRestart,\n onTerminate,\n onOpenTerminal,\n onShare,\n selected,\n onToggleSelect,\n}: {\n session: Session;\n onOpen?: (session: Session) => void;\n onStart?: (session: Session) => void;\n onStop?: (session: Session) => void;\n onRestart?: (session: Session) => void;\n onTerminate?: (session: Session) => void;\n onOpenTerminal?: (session: Session) => void;\n onShare?: (session: Session) => void;\n selected?: boolean;\n onToggleSelect?: () => void;\n}) {\n const tr = useTr();\n const [showMenu, setShowMenu] = useState(false);\n const isRunning = session.status === 'RUNNING';\n const isStopped = session.status === 'STOPPED' || session.status === 'TERMINATED';\n\n const formatTime = (timestamp: string | undefined | null) => {\n if (!timestamp) return 'Never';\n const diff = Date.now() - new Date(timestamp).getTime();\n if (diff < 60000) return 'Just now';\n if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;\n if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;\n return new Date(timestamp).toLocaleDateString();\n };\n\n return (\n <tr\n className={`border-b border-border-subtle hover:bg-bg-sunken/50 cursor-pointer transition-colors ${selected ? 'bg-action-primary-bg/5' : ''}`}\n onClick={() => onOpen?.(session)}\n >\n {/* Selection checkbox */}\n {onToggleSelect && (\n <td className=\"p-3 w-10\">\n <input\n aria-label=\"control\"\n type=\"checkbox\"\n checked={selected ?? false}\n onChange={(e) => {\n e.stopPropagation();\n onToggleSelect();\n }}\n onClick={(e) => e.stopPropagation()}\n className=\"size-4 rounded border-border-default text-action-primary-bg focus:ring-action-primary-bg\"\n />\n </td>\n )}\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <Terminal className=\"size-4 text-text-secondary shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{session.name}</p>\n {session.command && (\n <p className=\"text-xs font-mono text-text-muted truncate max-w-[200px]\">\n $ {session.command}\n </p>\n )}\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-sm\">{sessionTypeIcons[session.type] || '💻'}</span>\n <span className=\"text-sm text-text-secondary\">{session.type}</span>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <SessionStatusBadge status={session.status} />\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-sm text-text-secondary truncate block max-w-[120px]\">\n {session.agent?.name || '-'}\n </span>\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-sm text-text-secondary truncate block max-w-[120px]\">\n {session.vibe?.name || '-'}\n </span>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1.5 text-xs text-text-muted\">\n <Clock className=\"size-3\" />\n {formatTime(session.updatedAt)}\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1 justify-end\">\n {isStopped && onStart && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onStart(session);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Start\"\n >\n <Play className=\"size-3.5 text-text-secondary\" />\n </button>\n )}\n {isRunning && onStop && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onStop(session);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Stop\"\n >\n <Square className=\"size-3.5 text-text-secondary\" />\n </button>\n )}\n {isRunning && onRestart && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onRestart(session);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Restart\"\n >\n <RotateCcw className=\"size-3.5 text-text-secondary\" />\n </button>\n )}\n {isRunning && onOpenTerminal && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onOpenTerminal(session);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Open Terminal\"\n >\n <Terminal className=\"size-3.5 text-text-secondary\" />\n </button>\n )}\n {isRunning && onShare && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onShare(session);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Share Session\"\n >\n <Share2 className=\"size-3.5 text-text-secondary\" />\n </button>\n )}\n {onTerminate && (\n <div className=\"relative\">\n <button\n type=\"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=\"size-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 {onTerminate && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onTerminate(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-lg\"\n >\n {tr('vibecontrols.sessions.list.terminate', 'Terminate')}\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </td>\n </tr>\n );\n}\n\nexport function SessionList({\n sessions,\n onOpen,\n onStart,\n onStop,\n onRestart,\n onTerminate,\n onOpenTerminal,\n onShare,\n onCreateNew,\n isLoading,\n selectedIds,\n onToggleSelect,\n onSelectAll,\n onDeselectAll,\n}: SessionListProps) {\n const tr = useTr();\n const isAllSelected = selectedIds && sessions.length > 0 && selectedIds.size === sessions.length;\n\n if (!isLoading && sessions.length === 0) {\n return (\n <EmptyState\n icon={<Terminal className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.sessions.list.noSessionsTitle', 'No sessions yet')}\n description={tr(\n 'vibecontrols.sessions.list.noSessionsDescription',\n 'Sessions are terminal processes running on your agents. Start a session to run commands, scripts, or interactive shells.'\n )}\n action={\n onCreateNew && (\n <button\n type=\"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=\"size-4\" />\n {tr('vibecontrols.sessions.list.startSession', 'Start Session')}\n </button>\n )\n }\n />\n );\n }\n\n return (\n <div className=\"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 {onToggleSelect && (\n <th className=\"px-3 py-2.5 w-10\">\n <input\n aria-label=\"control\"\n type=\"checkbox\"\n checked={isAllSelected ?? false}\n onChange={() => {\n if (isAllSelected && onDeselectAll) {\n onDeselectAll();\n } else if (onSelectAll) {\n onSelectAll();\n }\n }}\n className=\"size-4 rounded border-border-default text-action-primary-bg focus:ring-action-primary-bg\"\n title={isAllSelected ? 'Deselect all' : 'Select all'}\n />\n </th>\n )}\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colName', 'Name')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colType', 'Type')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colStatus', 'Status')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colAgent', 'Agent')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colVibe', 'Vibe')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colUpdated', 'Updated')}\n </th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colActions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {sessions.map((session) => (\n <SessionRow\n key={session.id}\n session={session}\n onOpen={onOpen}\n onStart={onStart}\n onStop={onStop}\n onRestart={onRestart}\n onTerminate={onTerminate}\n onOpenTerminal={onOpenTerminal}\n onShare={onShare}\n selected={selectedIds?.has(session.id)}\n onToggleSelect={onToggleSelect ? () => onToggleSelect(session.id) : undefined}\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SessionList.js","names":[],"sources":["../../../src/components/sessions/SessionList.tsx"],"sourcesContent":["import type { Session } from './types';\nimport { SessionStatusBadge } from './SessionStatusBadge';\nimport { AgentInfoPopover, TargetInfoPopover } from './EntityInfoPopover';\nimport { EmptyState } from '../shared/EmptyState';\nimport { Terminal, Plus, Play, Square, RotateCcw, MoreVertical, Clock, Share2 } from 'lucide-react';\nimport { useState } from 'react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface SessionListProps {\n sessions: Session[];\n onOpen?: (session: Session) => void;\n onStart?: (session: Session) => void;\n onStop?: (session: Session) => void;\n onRestart?: (session: Session) => void;\n onTerminate?: (session: Session) => void;\n onOpenTerminal?: (session: Session) => void;\n onShare?: (session: Session) => void;\n onCreateNew?: () => void;\n isLoading?: boolean;\n /** Set of selected session IDs for bulk operations */\n selectedIds?: Set<string>;\n /** Toggle selection for a single session */\n onToggleSelect?: (sessionId: string) => void;\n /** Select all visible sessions */\n onSelectAll?: () => void;\n /** Deselect all sessions */\n onDeselectAll?: () => void;\n /**\n * Hide the table-header \"select all\" checkbox. Used when the list is\n * rendered inside a group (the group header owns selection instead),\n * so two competing select-alls don't fight over the same Set.\n */\n hideHeaderSelectAll?: boolean;\n}\n\nconst sessionTypeIcons: Record<string, string> = {\n TMUX: '🖥️',\n SSH: '🔐',\n TERMINAL: '💻',\n SCRIPT: '📜',\n CUSTOM: '⚙️',\n};\n\nfunction SessionRow({\n session,\n onOpen,\n onStart,\n onStop,\n onRestart,\n onTerminate,\n onOpenTerminal,\n onShare,\n selected,\n onToggleSelect,\n}: {\n session: Session;\n onOpen?: (session: Session) => void;\n onStart?: (session: Session) => void;\n onStop?: (session: Session) => void;\n onRestart?: (session: Session) => void;\n onTerminate?: (session: Session) => void;\n onOpenTerminal?: (session: Session) => void;\n onShare?: (session: Session) => void;\n selected?: boolean;\n onToggleSelect?: () => void;\n}) {\n const tr = useTr();\n const [showMenu, setShowMenu] = useState(false);\n const isRunning = session.status === 'RUNNING';\n const isStopped = session.status === 'STOPPED' || session.status === 'TERMINATED';\n\n const formatTime = (timestamp: string | undefined | null) => {\n if (!timestamp) return 'Never';\n const diff = Date.now() - new Date(timestamp).getTime();\n if (diff < 60000) return 'Just now';\n if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;\n if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;\n return new Date(timestamp).toLocaleDateString();\n };\n\n return (\n <tr\n className={`border-b border-border-subtle hover:bg-bg-sunken/50 cursor-pointer transition-colors ${selected ? 'bg-action-primary-bg/5' : ''}`}\n onClick={() => onOpen?.(session)}\n >\n {/* Selection checkbox */}\n {onToggleSelect && (\n <td className=\"p-3 w-10\">\n <input\n aria-label=\"control\"\n type=\"checkbox\"\n checked={selected ?? false}\n onChange={(e) => {\n e.stopPropagation();\n onToggleSelect();\n }}\n onClick={(e) => e.stopPropagation()}\n className=\"size-4 rounded border-border-default text-action-primary-bg focus:ring-action-primary-bg\"\n />\n </td>\n )}\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <Terminal className=\"size-4 text-text-secondary shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{session.name}</p>\n {session.command && (\n <p className=\"text-xs font-mono text-text-muted truncate max-w-[200px]\">\n $ {session.command}\n </p>\n )}\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-sm\">{sessionTypeIcons[session.type] || '💻'}</span>\n <span className=\"text-sm text-text-secondary\">{session.type}</span>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <SessionStatusBadge status={session.status} />\n </td>\n <td className=\"px-4 py-3\">\n {session.agent ? (\n <AgentInfoPopover agent={session.agent} />\n ) : (\n <span className=\"text-sm text-text-secondary\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n {session.agent?.target ? (\n <TargetInfoPopover target={session.agent.target} />\n ) : (\n <span className=\"text-sm text-text-secondary\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-sm text-text-secondary truncate block max-w-[120px]\">\n {session.vibe?.name || '-'}\n </span>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1.5 text-xs text-text-muted\">\n <Clock className=\"size-3\" />\n {formatTime(session.updatedAt)}\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1 justify-end\">\n {isStopped && onStart && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onStart(session);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Start\"\n >\n <Play className=\"size-3.5 text-text-secondary\" />\n </button>\n )}\n {isRunning && onStop && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onStop(session);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Stop\"\n >\n <Square className=\"size-3.5 text-text-secondary\" />\n </button>\n )}\n {isRunning && onRestart && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onRestart(session);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Restart\"\n >\n <RotateCcw className=\"size-3.5 text-text-secondary\" />\n </button>\n )}\n {isRunning && onOpenTerminal && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onOpenTerminal(session);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Open Terminal\"\n >\n <Terminal className=\"size-3.5 text-text-secondary\" />\n </button>\n )}\n {isRunning && onShare && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onShare(session);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n title=\"Share Session\"\n >\n <Share2 className=\"size-3.5 text-text-secondary\" />\n </button>\n )}\n {onTerminate && (\n <div className=\"relative\">\n <button\n type=\"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=\"size-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 {onTerminate && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onTerminate(session);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-lg\"\n >\n {tr('vibecontrols.sessions.list.terminate', 'Terminate')}\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </td>\n </tr>\n );\n}\n\nexport function SessionList({\n sessions,\n onOpen,\n onStart,\n onStop,\n onRestart,\n onTerminate,\n onOpenTerminal,\n onShare,\n onCreateNew,\n isLoading,\n selectedIds,\n onToggleSelect,\n onSelectAll,\n onDeselectAll,\n hideHeaderSelectAll = false,\n}: SessionListProps) {\n const tr = useTr();\n const isAllSelected = selectedIds && sessions.length > 0 && selectedIds.size === sessions.length;\n\n if (!isLoading && sessions.length === 0) {\n return (\n <EmptyState\n icon={<Terminal className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.sessions.list.noSessionsTitle', 'No sessions yet')}\n description={tr(\n 'vibecontrols.sessions.list.noSessionsDescription',\n 'Sessions are terminal processes running on your agents. Start a session to run commands, scripts, or interactive shells.'\n )}\n action={\n onCreateNew && (\n <button\n type=\"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=\"size-4\" />\n {tr('vibecontrols.sessions.list.startSession', 'Start Session')}\n </button>\n )\n }\n />\n );\n }\n\n return (\n <div className=\"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 {onToggleSelect && hideHeaderSelectAll && <th className=\"px-3 py-2.5 w-10\" />}\n {onToggleSelect && !hideHeaderSelectAll && (\n <th className=\"px-3 py-2.5 w-10\">\n <input\n aria-label=\"control\"\n type=\"checkbox\"\n checked={isAllSelected ?? false}\n onChange={() => {\n if (isAllSelected && onDeselectAll) {\n onDeselectAll();\n } else if (onSelectAll) {\n onSelectAll();\n }\n }}\n className=\"size-4 rounded border-border-default text-action-primary-bg focus:ring-action-primary-bg\"\n title={isAllSelected ? 'Deselect all' : 'Select all'}\n />\n </th>\n )}\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colName', 'Name')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colType', 'Type')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colStatus', 'Status')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colAgent', 'Agent')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colTarget', 'Target')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colVibe', 'Vibe')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colUpdated', 'Updated')}\n </th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.sessions.list.colActions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {sessions.map((session) => (\n <SessionRow\n key={session.id}\n session={session}\n onOpen={onOpen}\n onStart={onStart}\n onStop={onStop}\n onRestart={onRestart}\n onTerminate={onTerminate}\n onOpenTerminal={onOpenTerminal}\n onShare={onShare}\n selected={selectedIds?.has(session.id)}\n onToggleSelect={onToggleSelect ? () => onToggleSelect(session.id) : undefined}\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}