@burdenoff/microfe-vibecontrols 2026.528.7 → 2026.528.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/VibeControlsRoot.js +1 -0
- package/dist/VibeControlsRoot.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerInputArea.js +70 -64
- package/dist/components/agent-manager/AgentManagerInputArea.js.map +1 -1
- package/dist/components/audit/AuditLogFilters.js +71 -47
- package/dist/components/audit/AuditLogFilters.js.map +1 -1
- package/dist/components/shared/AgentSetupBanner.js +50 -45
- package/dist/components/shared/AgentSetupBanner.js.map +1 -1
- package/dist/components/shared/LinkToVibePanel.js +97 -0
- package/dist/components/shared/LinkToVibePanel.js.map +1 -0
- package/dist/components/shared/index.js +1 -0
- package/dist/components/vibe/VibeLinkedEntitiesPanel.js +60 -0
- package/dist/components/vibe/VibeLinkedEntitiesPanel.js.map +1 -0
- package/dist/components/vibedeck/VibeDeckButtonTile.js +25 -23
- package/dist/components/vibedeck/VibeDeckButtonTile.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckGrid.js +2 -2
- package/dist/components/vibedeck/VibeDeckGrid.js.map +1 -1
- package/dist/microfe-vibecontrols.css +1 -1
- package/dist/pages/AgentDetailsPage.js +2 -2
- package/dist/pages/AgentDetailsPage.js.map +1 -1
- package/dist/pages/AnalyticsPage.js +255 -204
- package/dist/pages/AnalyticsPage.js.map +1 -1
- package/dist/pages/OverviewPage.js +1 -11
- package/dist/pages/OverviewPage.js.map +1 -1
- package/dist/pages/SessionsPage.js +825 -629
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/VibeAuditPage.js +184 -153
- package/dist/pages/VibeAuditPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js +416 -379
- package/dist/pages/VibeDeckPage.js.map +1 -1
- package/dist/pages/VibeDetailsPage.js +621 -557
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/tunnels/TunnelsTab.js +115 -90
- package/dist/pages/tunnels/TunnelsTab.js.map +1 -1
- package/dist/services/schedulerApi.js +37 -15
- package/dist/services/schedulerApi.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,169 +4,193 @@ import "../shared/index.js";
|
|
|
4
4
|
import { useI18n as n } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
5
5
|
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
6
6
|
//#region src/components/audit/AuditLogFilters.tsx
|
|
7
|
-
function a({ searchQuery: a, onSearchChange: o, actionFilter: s, onActionChange: c, resourceTypeFilter: l, onResourceTypeChange: u, statusFilter: d, onStatusChange: f, hasCommandFilter: p, onHasCommandChange: m }) {
|
|
8
|
-
let { t:
|
|
9
|
-
let n =
|
|
7
|
+
function a({ searchQuery: a, onSearchChange: o, actionFilter: s, onActionChange: c, resourceTypeFilter: l, onResourceTypeChange: u, statusFilter: d, onStatusChange: f, hasCommandFilter: p, onHasCommandChange: m, agentFilter: h, onAgentChange: g, agents: _, vibeFilter: v, onVibeChange: y, vibes: b }) {
|
|
8
|
+
let { t: x } = n(), S = (e, t) => {
|
|
9
|
+
let n = x(e);
|
|
10
10
|
return n === e ? t : n;
|
|
11
|
-
},
|
|
11
|
+
}, C = [
|
|
12
12
|
{
|
|
13
13
|
value: "all",
|
|
14
|
-
label:
|
|
14
|
+
label: S("audit.allActions", "All Actions")
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
value: "CREATE",
|
|
18
|
-
label:
|
|
18
|
+
label: S("audit.actionCreate", "Create")
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
value: "UPDATE",
|
|
22
|
-
label:
|
|
22
|
+
label: S("audit.actionUpdate", "Update")
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
value: "DELETE",
|
|
26
|
-
label:
|
|
26
|
+
label: S("audit.actionDelete", "Delete")
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
value: "EXECUTE",
|
|
30
|
-
label:
|
|
30
|
+
label: S("audit.actionExecute", "Execute")
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
value: "EXPORT",
|
|
34
|
-
label:
|
|
34
|
+
label: S("audit.actionExport", "Export")
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
value: "SHARE",
|
|
38
|
-
label:
|
|
38
|
+
label: S("audit.actionShare", "Share")
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
value: "REVOKE",
|
|
42
|
-
label:
|
|
42
|
+
label: S("audit.actionRevoke", "Revoke")
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
value: "ARCHIVE",
|
|
46
|
-
label:
|
|
46
|
+
label: S("audit.actionArchive", "Archive")
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
49
|
value: "RESTORE",
|
|
50
|
-
label:
|
|
50
|
+
label: S("audit.actionRestore", "Restore")
|
|
51
51
|
}
|
|
52
|
-
],
|
|
52
|
+
], w = [
|
|
53
53
|
{
|
|
54
54
|
value: "all",
|
|
55
|
-
label:
|
|
55
|
+
label: S("audit.allResources", "All Resources")
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
value: "AGENT",
|
|
59
|
-
label:
|
|
59
|
+
label: S("audit.resourceAgent", "Agent")
|
|
60
60
|
},
|
|
61
61
|
{
|
|
62
62
|
value: "VIBE",
|
|
63
|
-
label:
|
|
63
|
+
label: S("audit.resourceVibe", "Vibe")
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
value: "SESSION",
|
|
67
|
-
label:
|
|
67
|
+
label: S("audit.resourceSession", "Session")
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
70
|
value: "VIBE_DECK",
|
|
71
|
-
label:
|
|
71
|
+
label: S("audit.resourceVibeDeck", "Vibe Deck")
|
|
72
72
|
},
|
|
73
73
|
{
|
|
74
74
|
value: "VIBE_DECK_BUTTON",
|
|
75
|
-
label:
|
|
75
|
+
label: S("audit.resourceDeckButton", "Deck Button")
|
|
76
76
|
},
|
|
77
77
|
{
|
|
78
78
|
value: "NOTE",
|
|
79
|
-
label:
|
|
79
|
+
label: S("audit.resourceNote", "Note")
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
82
|
value: "CONFIGURATION",
|
|
83
|
-
label:
|
|
83
|
+
label: S("audit.resourceConfiguration", "Configuration")
|
|
84
84
|
},
|
|
85
85
|
{
|
|
86
86
|
value: "WEBHOOK",
|
|
87
|
-
label:
|
|
87
|
+
label: S("audit.resourceWebhook", "Webhook")
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
90
|
value: "SESSION_SHARE",
|
|
91
|
-
label:
|
|
91
|
+
label: S("audit.resourceSessionShare", "Session Share")
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
value: "AI_TOOL_EVENT",
|
|
95
|
-
label:
|
|
95
|
+
label: S("audit.resourceAiToolEvent", "AI Tool Event")
|
|
96
96
|
},
|
|
97
97
|
{
|
|
98
98
|
value: "AUDIT_LOG",
|
|
99
|
-
label:
|
|
99
|
+
label: S("audit.resourceAuditLog", "Audit Log")
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
102
|
value: "CALENDAR_TASK",
|
|
103
|
-
label:
|
|
103
|
+
label: S("audit.resourceCalendarTask", "Calendar Task")
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
106
|
value: "TARGET",
|
|
107
|
-
label:
|
|
107
|
+
label: S("audit.resourceTarget", "Target")
|
|
108
108
|
},
|
|
109
109
|
{
|
|
110
110
|
value: "AGENT_CONNECTION",
|
|
111
|
-
label:
|
|
111
|
+
label: S("audit.resourceAgentConnection", "Agent Connection")
|
|
112
112
|
},
|
|
113
113
|
{
|
|
114
114
|
value: "UI_SESSION",
|
|
115
|
-
label:
|
|
115
|
+
label: S("audit.resourceUiSession", "UI Session")
|
|
116
116
|
},
|
|
117
117
|
{
|
|
118
118
|
value: "SESSION_SHARE_LINK",
|
|
119
|
-
label:
|
|
119
|
+
label: S("audit.resourceShareLink", "Share Link")
|
|
120
120
|
}
|
|
121
|
-
],
|
|
121
|
+
], T = [
|
|
122
122
|
{
|
|
123
123
|
value: "all",
|
|
124
|
-
label:
|
|
124
|
+
label: S("audit.allStatuses", "All Statuses")
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
value: "SUCCESS",
|
|
128
|
-
label:
|
|
128
|
+
label: S("audit.statusSuccess", "Success")
|
|
129
129
|
},
|
|
130
130
|
{
|
|
131
131
|
value: "FAILURE",
|
|
132
|
-
label:
|
|
132
|
+
label: S("audit.statusFailure", "Failure")
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
value: "DENIED",
|
|
136
|
-
label:
|
|
136
|
+
label: S("audit.statusDenied", "Denied")
|
|
137
137
|
},
|
|
138
138
|
{
|
|
139
139
|
value: "ERROR",
|
|
140
|
-
label:
|
|
140
|
+
label: S("audit.statusError", "Error")
|
|
141
141
|
}
|
|
142
|
-
]
|
|
142
|
+
], E = [{
|
|
143
|
+
value: "all",
|
|
144
|
+
label: S("audit.allAgents", "All Agents")
|
|
145
|
+
}, ...(_ ?? []).map((e) => ({
|
|
146
|
+
value: e.id,
|
|
147
|
+
label: e.name
|
|
148
|
+
}))], D = [{
|
|
149
|
+
value: "all",
|
|
150
|
+
label: S("audit.allVibes", "All Vibes")
|
|
151
|
+
}, ...(b ?? []).map((e) => ({
|
|
152
|
+
value: e.id,
|
|
153
|
+
label: e.name
|
|
154
|
+
}))];
|
|
143
155
|
return /* @__PURE__ */ i("div", {
|
|
144
156
|
className: "mb-4 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center",
|
|
145
157
|
children: [
|
|
146
158
|
/* @__PURE__ */ r(e, {
|
|
147
159
|
value: a,
|
|
148
160
|
onChange: o,
|
|
149
|
-
placeholder:
|
|
161
|
+
placeholder: S("audit.searchPlaceholder", "Search audit logs..."),
|
|
150
162
|
className: "w-full sm:w-64"
|
|
151
163
|
}),
|
|
152
164
|
/* @__PURE__ */ r(t, {
|
|
153
|
-
label:
|
|
154
|
-
options:
|
|
165
|
+
label: S("audit.action", "Action"),
|
|
166
|
+
options: C,
|
|
155
167
|
value: s,
|
|
156
168
|
onChange: c
|
|
157
169
|
}),
|
|
158
170
|
/* @__PURE__ */ r(t, {
|
|
159
|
-
label:
|
|
160
|
-
options:
|
|
171
|
+
label: S("audit.resource", "Resource"),
|
|
172
|
+
options: w,
|
|
161
173
|
value: l,
|
|
162
174
|
onChange: u
|
|
163
175
|
}),
|
|
164
176
|
/* @__PURE__ */ r(t, {
|
|
165
|
-
label:
|
|
166
|
-
options:
|
|
177
|
+
label: S("audit.status", "Status"),
|
|
178
|
+
options: T,
|
|
167
179
|
value: d,
|
|
168
180
|
onChange: f
|
|
169
181
|
}),
|
|
182
|
+
g && /* @__PURE__ */ r(t, {
|
|
183
|
+
label: S("audit.agent", "Agent"),
|
|
184
|
+
options: E,
|
|
185
|
+
value: h ?? "all",
|
|
186
|
+
onChange: g
|
|
187
|
+
}),
|
|
188
|
+
y && /* @__PURE__ */ r(t, {
|
|
189
|
+
label: S("audit.vibe", "Vibe"),
|
|
190
|
+
options: D,
|
|
191
|
+
value: v ?? "all",
|
|
192
|
+
onChange: y
|
|
193
|
+
}),
|
|
170
194
|
/* @__PURE__ */ i("label", {
|
|
171
195
|
className: "flex items-center gap-2 text-sm text-text-secondary cursor-pointer",
|
|
172
196
|
children: [/* @__PURE__ */ r("input", {
|
|
@@ -175,7 +199,7 @@ function a({ searchQuery: a, onSearchChange: o, actionFilter: s, onActionChange:
|
|
|
175
199
|
checked: p,
|
|
176
200
|
onChange: (e) => m(e.target.checked),
|
|
177
201
|
className: "rounded border-border-primary"
|
|
178
|
-
}),
|
|
202
|
+
}), S("audit.commandsOnly", "Commands only")]
|
|
179
203
|
})
|
|
180
204
|
]
|
|
181
205
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuditLogFilters.js","names":[],"sources":["../../../src/components/audit/AuditLogFilters.tsx"],"sourcesContent":["import { SearchInput, FilterDropdown } from '@/components/shared';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface AuditLogFiltersProps {\n searchQuery: string;\n onSearchChange: (query: string) => void;\n actionFilter: string | null;\n onActionChange: (value: string) => void;\n resourceTypeFilter: string | null;\n onResourceTypeChange: (value: string) => void;\n statusFilter: string | null;\n onStatusChange: (value: string) => void;\n hasCommandFilter: boolean;\n onHasCommandChange: (value: boolean) => void;\n}\n\nexport function AuditLogFilters({\n searchQuery,\n onSearchChange,\n actionFilter,\n onActionChange,\n resourceTypeFilter,\n onResourceTypeChange,\n statusFilter,\n onStatusChange,\n hasCommandFilter,\n onHasCommandChange,\n}: AuditLogFiltersProps) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n const actionOptions = [\n { value: 'all', label: tr('audit.allActions', 'All Actions') },\n { value: 'CREATE', label: tr('audit.actionCreate', 'Create') },\n { value: 'UPDATE', label: tr('audit.actionUpdate', 'Update') },\n { value: 'DELETE', label: tr('audit.actionDelete', 'Delete') },\n { value: 'EXECUTE', label: tr('audit.actionExecute', 'Execute') },\n { value: 'EXPORT', label: tr('audit.actionExport', 'Export') },\n { value: 'SHARE', label: tr('audit.actionShare', 'Share') },\n { value: 'REVOKE', label: tr('audit.actionRevoke', 'Revoke') },\n { value: 'ARCHIVE', label: tr('audit.actionArchive', 'Archive') },\n { value: 'RESTORE', label: tr('audit.actionRestore', 'Restore') },\n ];\n\n const resourceTypeOptions = [\n { value: 'all', label: tr('audit.allResources', 'All Resources') },\n { value: 'AGENT', label: tr('audit.resourceAgent', 'Agent') },\n { value: 'VIBE', label: tr('audit.resourceVibe', 'Vibe') },\n { value: 'SESSION', label: tr('audit.resourceSession', 'Session') },\n { value: 'VIBE_DECK', label: tr('audit.resourceVibeDeck', 'Vibe Deck') },\n { value: 'VIBE_DECK_BUTTON', label: tr('audit.resourceDeckButton', 'Deck Button') },\n { value: 'NOTE', label: tr('audit.resourceNote', 'Note') },\n { value: 'CONFIGURATION', label: tr('audit.resourceConfiguration', 'Configuration') },\n { value: 'WEBHOOK', label: tr('audit.resourceWebhook', 'Webhook') },\n { value: 'SESSION_SHARE', label: tr('audit.resourceSessionShare', 'Session Share') },\n { value: 'AI_TOOL_EVENT', label: tr('audit.resourceAiToolEvent', 'AI Tool Event') },\n { value: 'AUDIT_LOG', label: tr('audit.resourceAuditLog', 'Audit Log') },\n { value: 'CALENDAR_TASK', label: tr('audit.resourceCalendarTask', 'Calendar Task') },\n { value: 'TARGET', label: tr('audit.resourceTarget', 'Target') },\n { value: 'AGENT_CONNECTION', label: tr('audit.resourceAgentConnection', 'Agent Connection') },\n { value: 'UI_SESSION', label: tr('audit.resourceUiSession', 'UI Session') },\n { value: 'SESSION_SHARE_LINK', label: tr('audit.resourceShareLink', 'Share Link') },\n ];\n\n const statusOptions = [\n { value: 'all', label: tr('audit.allStatuses', 'All Statuses') },\n { value: 'SUCCESS', label: tr('audit.statusSuccess', 'Success') },\n { value: 'FAILURE', label: tr('audit.statusFailure', 'Failure') },\n { value: 'DENIED', label: tr('audit.statusDenied', 'Denied') },\n { value: 'ERROR', label: tr('audit.statusError', 'Error') },\n ];\n\n return (\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center\">\n <SearchInput\n value={searchQuery}\n onChange={onSearchChange}\n placeholder={tr('audit.searchPlaceholder', 'Search audit logs...')}\n className=\"w-full sm:w-64\"\n />\n <FilterDropdown\n label={tr('audit.action', 'Action')}\n options={actionOptions}\n value={actionFilter}\n onChange={onActionChange}\n />\n <FilterDropdown\n label={tr('audit.resource', 'Resource')}\n options={resourceTypeOptions}\n value={resourceTypeFilter}\n onChange={onResourceTypeChange}\n />\n <FilterDropdown\n label={tr('audit.status', 'Status')}\n options={statusOptions}\n value={statusFilter}\n onChange={onStatusChange}\n />\n <label className=\"flex items-center gap-2 text-sm text-text-secondary cursor-pointer\">\n <input\n aria-label=\"control\"\n type=\"checkbox\"\n checked={hasCommandFilter}\n onChange={(e) => onHasCommandChange(e.target.checked)}\n className=\"rounded border-border-primary\"\n />\n {tr('audit.commandsOnly', 'Commands only')}\n </label>\n </div>\n );\n}\n"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"AuditLogFilters.js","names":[],"sources":["../../../src/components/audit/AuditLogFilters.tsx"],"sourcesContent":["import { SearchInput, FilterDropdown } from '@/components/shared';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface AgentOption {\n id: string;\n name: string;\n}\n\ninterface VibeOption {\n id: string;\n name: string;\n}\n\ninterface AuditLogFiltersProps {\n searchQuery: string;\n onSearchChange: (query: string) => void;\n actionFilter: string | null;\n onActionChange: (value: string) => void;\n resourceTypeFilter: string | null;\n onResourceTypeChange: (value: string) => void;\n statusFilter: string | null;\n onStatusChange: (value: string) => void;\n hasCommandFilter: boolean;\n onHasCommandChange: (value: boolean) => void;\n agentFilter?: string | null;\n onAgentChange?: (value: string) => void;\n agents?: AgentOption[];\n vibeFilter?: string | null;\n onVibeChange?: (value: string) => void;\n vibes?: VibeOption[];\n}\n\nexport function AuditLogFilters({\n searchQuery,\n onSearchChange,\n actionFilter,\n onActionChange,\n resourceTypeFilter,\n onResourceTypeChange,\n statusFilter,\n onStatusChange,\n hasCommandFilter,\n onHasCommandChange,\n agentFilter,\n onAgentChange,\n agents,\n vibeFilter,\n onVibeChange,\n vibes,\n}: AuditLogFiltersProps) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n const actionOptions = [\n { value: 'all', label: tr('audit.allActions', 'All Actions') },\n { value: 'CREATE', label: tr('audit.actionCreate', 'Create') },\n { value: 'UPDATE', label: tr('audit.actionUpdate', 'Update') },\n { value: 'DELETE', label: tr('audit.actionDelete', 'Delete') },\n { value: 'EXECUTE', label: tr('audit.actionExecute', 'Execute') },\n { value: 'EXPORT', label: tr('audit.actionExport', 'Export') },\n { value: 'SHARE', label: tr('audit.actionShare', 'Share') },\n { value: 'REVOKE', label: tr('audit.actionRevoke', 'Revoke') },\n { value: 'ARCHIVE', label: tr('audit.actionArchive', 'Archive') },\n { value: 'RESTORE', label: tr('audit.actionRestore', 'Restore') },\n ];\n\n const resourceTypeOptions = [\n { value: 'all', label: tr('audit.allResources', 'All Resources') },\n { value: 'AGENT', label: tr('audit.resourceAgent', 'Agent') },\n { value: 'VIBE', label: tr('audit.resourceVibe', 'Vibe') },\n { value: 'SESSION', label: tr('audit.resourceSession', 'Session') },\n { value: 'VIBE_DECK', label: tr('audit.resourceVibeDeck', 'Vibe Deck') },\n { value: 'VIBE_DECK_BUTTON', label: tr('audit.resourceDeckButton', 'Deck Button') },\n { value: 'NOTE', label: tr('audit.resourceNote', 'Note') },\n { value: 'CONFIGURATION', label: tr('audit.resourceConfiguration', 'Configuration') },\n { value: 'WEBHOOK', label: tr('audit.resourceWebhook', 'Webhook') },\n { value: 'SESSION_SHARE', label: tr('audit.resourceSessionShare', 'Session Share') },\n { value: 'AI_TOOL_EVENT', label: tr('audit.resourceAiToolEvent', 'AI Tool Event') },\n { value: 'AUDIT_LOG', label: tr('audit.resourceAuditLog', 'Audit Log') },\n { value: 'CALENDAR_TASK', label: tr('audit.resourceCalendarTask', 'Calendar Task') },\n { value: 'TARGET', label: tr('audit.resourceTarget', 'Target') },\n { value: 'AGENT_CONNECTION', label: tr('audit.resourceAgentConnection', 'Agent Connection') },\n { value: 'UI_SESSION', label: tr('audit.resourceUiSession', 'UI Session') },\n { value: 'SESSION_SHARE_LINK', label: tr('audit.resourceShareLink', 'Share Link') },\n ];\n\n const statusOptions = [\n { value: 'all', label: tr('audit.allStatuses', 'All Statuses') },\n { value: 'SUCCESS', label: tr('audit.statusSuccess', 'Success') },\n { value: 'FAILURE', label: tr('audit.statusFailure', 'Failure') },\n { value: 'DENIED', label: tr('audit.statusDenied', 'Denied') },\n { value: 'ERROR', label: tr('audit.statusError', 'Error') },\n ];\n\n const agentOptions = [\n { value: 'all', label: tr('audit.allAgents', 'All Agents') },\n ...(agents ?? []).map((a) => ({ value: a.id, label: a.name })),\n ];\n\n const vibeOptions = [\n { value: 'all', label: tr('audit.allVibes', 'All Vibes') },\n ...(vibes ?? []).map((v) => ({ value: v.id, label: v.name })),\n ];\n\n return (\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center\">\n <SearchInput\n value={searchQuery}\n onChange={onSearchChange}\n placeholder={tr('audit.searchPlaceholder', 'Search audit logs...')}\n className=\"w-full sm:w-64\"\n />\n <FilterDropdown\n label={tr('audit.action', 'Action')}\n options={actionOptions}\n value={actionFilter}\n onChange={onActionChange}\n />\n <FilterDropdown\n label={tr('audit.resource', 'Resource')}\n options={resourceTypeOptions}\n value={resourceTypeFilter}\n onChange={onResourceTypeChange}\n />\n <FilterDropdown\n label={tr('audit.status', 'Status')}\n options={statusOptions}\n value={statusFilter}\n onChange={onStatusChange}\n />\n {onAgentChange && (\n <FilterDropdown\n label={tr('audit.agent', 'Agent')}\n options={agentOptions}\n value={agentFilter ?? 'all'}\n onChange={onAgentChange}\n />\n )}\n {onVibeChange && (\n <FilterDropdown\n label={tr('audit.vibe', 'Vibe')}\n options={vibeOptions}\n value={vibeFilter ?? 'all'}\n onChange={onVibeChange}\n />\n )}\n <label className=\"flex items-center gap-2 text-sm text-text-secondary cursor-pointer\">\n <input\n aria-label=\"control\"\n type=\"checkbox\"\n checked={hasCommandFilter}\n onChange={(e) => onHasCommandChange(e.target.checked)}\n className=\"rounded border-border-primary\"\n />\n {tr('audit.commandsOnly', 'Commands only')}\n </label>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -6,31 +6,32 @@ import { Check as o, Copy as s, Download as c, ExternalLink as l, Terminal as u,
|
|
|
6
6
|
import { getProfileScopedKey as f } from "@burdenoff/fe-libs/shared/utils";
|
|
7
7
|
import { AnimatePresence as p, motion as m } from "framer-motion";
|
|
8
8
|
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
9
|
+
import { Button as _ } from "@burdenoff/fe-libs/ui";
|
|
9
10
|
//#region src/components/shared/AgentSetupBanner.tsx
|
|
10
|
-
var
|
|
11
|
-
function
|
|
11
|
+
var v = "https://www.npmjs.com/package/@vibecontrols/agent";
|
|
12
|
+
function y() {
|
|
12
13
|
return typeof window > "u" ? "curl -fsSL https://app.vibecontrols.com/install | bash" : `curl -fsSL https://${window.__VIBECONTROLS_HOST__ ?? window.location.host}/install | bash`;
|
|
13
14
|
}
|
|
14
|
-
function
|
|
15
|
-
let
|
|
15
|
+
function b({ variant: b = "compact", dismissible: x = !0, dismissKey: S = "vibecontrols-setup-banner-dismissed", className: C = "" }) {
|
|
16
|
+
let w = e(), T = t(), E = i(() => y(), []), [D, O] = a(!1), [k, A] = a(() => {
|
|
16
17
|
try {
|
|
17
|
-
return localStorage.getItem(f(
|
|
18
|
+
return localStorage.getItem(f(S)) === "true";
|
|
18
19
|
} catch {
|
|
19
20
|
return !1;
|
|
20
21
|
}
|
|
21
|
-
}),
|
|
22
|
+
}), j = r(async (e) => {
|
|
22
23
|
try {
|
|
23
|
-
await navigator.clipboard.writeText(e),
|
|
24
|
+
await navigator.clipboard.writeText(e), O(!0), setTimeout(() => O(!1), 2e3);
|
|
24
25
|
} catch {
|
|
25
26
|
let t = document.createElement("textarea");
|
|
26
|
-
t.value = e, document.body.appendChild(t), t.select(), document.execCommand("copy"), document.body.removeChild(t),
|
|
27
|
+
t.value = e, document.body.appendChild(t), t.select(), document.execCommand("copy"), document.body.removeChild(t), O(!0), setTimeout(() => O(!1), 2e3);
|
|
27
28
|
}
|
|
28
|
-
}, []),
|
|
29
|
-
|
|
29
|
+
}, []), M = r(() => {
|
|
30
|
+
A(!0);
|
|
30
31
|
try {
|
|
31
|
-
localStorage.setItem(f(
|
|
32
|
+
localStorage.setItem(f(S), "true");
|
|
32
33
|
} catch {}
|
|
33
|
-
}, [
|
|
34
|
+
}, [S]), N = {
|
|
34
35
|
duration: .3,
|
|
35
36
|
ease: [
|
|
36
37
|
.4,
|
|
@@ -39,7 +40,7 @@ function y({ variant: y = "compact", dismissible: b = !0, dismissKey: x = "vibec
|
|
|
39
40
|
1
|
|
40
41
|
]
|
|
41
42
|
};
|
|
42
|
-
return
|
|
43
|
+
return b === "compact" ? /* @__PURE__ */ h(p, { children: !k && /* @__PURE__ */ g(m.div, {
|
|
43
44
|
initial: {
|
|
44
45
|
opacity: 0,
|
|
45
46
|
y: -8,
|
|
@@ -55,8 +56,8 @@ function y({ variant: y = "compact", dismissible: b = !0, dismissKey: x = "vibec
|
|
|
55
56
|
y: -8,
|
|
56
57
|
height: 0
|
|
57
58
|
},
|
|
58
|
-
transition:
|
|
59
|
-
className: `relative flex flex-col items-start gap-3 px-4 py-3 bg-accent-purple-subtle border border-accent-purple/20 rounded-lg sm:flex-row sm:items-center ${
|
|
59
|
+
transition: N,
|
|
60
|
+
className: `relative flex flex-col items-start gap-3 px-4 py-3 bg-accent-purple-subtle border border-accent-purple/20 rounded-lg sm:flex-row sm:items-center ${C}`,
|
|
60
61
|
children: [
|
|
61
62
|
/* @__PURE__ */ h(c, { className: "size-5 text-accent-purple flex-shrink-0" }),
|
|
62
63
|
/* @__PURE__ */ g("div", {
|
|
@@ -64,42 +65,42 @@ function y({ variant: y = "compact", dismissible: b = !0, dismissKey: x = "vibec
|
|
|
64
65
|
children: [
|
|
65
66
|
/* @__PURE__ */ h("span", {
|
|
66
67
|
className: "text-sm font-medium text-text-primary",
|
|
67
|
-
children:
|
|
68
|
+
children: w("vibecontrols.shared.agentSetupBanner.installPrompt", "Install the VibeControls Agent CLI to get started")
|
|
68
69
|
}),
|
|
69
70
|
/* @__PURE__ */ g("code", {
|
|
70
71
|
className: "inline-flex min-w-0 max-w-full items-center gap-1.5 rounded border border-border-default bg-bg-sunken px-2.5 py-1 font-mono text-xs text-text-primary transition-colors hover:bg-bg-elevated",
|
|
71
|
-
onClick: () =>
|
|
72
|
-
title:
|
|
72
|
+
onClick: () => j(E),
|
|
73
|
+
title: w("vibecontrols.shared.agentSetupBanner.clickToCopy", "Click to copy"),
|
|
73
74
|
children: [
|
|
74
75
|
/* @__PURE__ */ h(u, { className: "size-3" }),
|
|
75
76
|
/* @__PURE__ */ h("span", {
|
|
76
77
|
className: "min-w-0 break-all",
|
|
77
|
-
children:
|
|
78
|
+
children: E
|
|
78
79
|
}),
|
|
79
|
-
|
|
80
|
+
D ? /* @__PURE__ */ h(o, { className: "size-3 text-status-success-text" }) : /* @__PURE__ */ h(s, { className: "size-3 text-text-muted" })
|
|
80
81
|
]
|
|
81
82
|
}),
|
|
82
83
|
/* @__PURE__ */ g("button", {
|
|
83
84
|
type: "button",
|
|
84
|
-
onClick: () =>
|
|
85
|
+
onClick: () => T("/getting-started"),
|
|
85
86
|
className: "text-sm text-accent-purple hover:underline flex items-center gap-1",
|
|
86
87
|
children: [
|
|
87
|
-
|
|
88
|
+
w("vibecontrols.shared.agentSetupBanner.setupGuide", "Setup guide"),
|
|
88
89
|
" ",
|
|
89
90
|
/* @__PURE__ */ h(l, { className: "size-3" })
|
|
90
91
|
]
|
|
91
92
|
})
|
|
92
93
|
]
|
|
93
94
|
}),
|
|
94
|
-
|
|
95
|
+
x && /* @__PURE__ */ h("button", {
|
|
95
96
|
type: "button",
|
|
96
|
-
onClick:
|
|
97
|
+
onClick: M,
|
|
97
98
|
className: "flex-shrink-0 p-1 text-text-muted hover:text-text-secondary rounded transition-colors",
|
|
98
|
-
title:
|
|
99
|
+
title: w("vibecontrols.shared.agentSetupBanner.dismiss", "Dismiss"),
|
|
99
100
|
children: /* @__PURE__ */ h(d, { className: "size-4" })
|
|
100
101
|
})
|
|
101
102
|
]
|
|
102
|
-
}) }) : /* @__PURE__ */ h(p, { children: !
|
|
103
|
+
}) }) : /* @__PURE__ */ h(p, { children: !k && /* @__PURE__ */ g(m.div, {
|
|
103
104
|
initial: {
|
|
104
105
|
opacity: 0,
|
|
105
106
|
y: -8,
|
|
@@ -115,13 +116,13 @@ function y({ variant: y = "compact", dismissible: b = !0, dismissKey: x = "vibec
|
|
|
115
116
|
y: -8,
|
|
116
117
|
height: 0
|
|
117
118
|
},
|
|
118
|
-
transition:
|
|
119
|
-
className: `relative border border-accent-purple/20 bg-accent-purple-subtle rounded-lg overflow-hidden ${
|
|
120
|
-
children: [
|
|
119
|
+
transition: N,
|
|
120
|
+
className: `relative border border-accent-purple/20 bg-accent-purple-subtle rounded-lg overflow-hidden ${C}`,
|
|
121
|
+
children: [x && /* @__PURE__ */ h("button", {
|
|
121
122
|
type: "button",
|
|
122
|
-
onClick:
|
|
123
|
+
onClick: M,
|
|
123
124
|
className: "absolute top-3 right-3 p-1 text-text-muted hover:text-text-secondary rounded transition-colors z-10",
|
|
124
|
-
title:
|
|
125
|
+
title: w("vibecontrols.shared.agentSetupBanner.dismiss", "Dismiss"),
|
|
125
126
|
children: /* @__PURE__ */ h(d, { className: "size-4" })
|
|
126
127
|
}), /* @__PURE__ */ g("div", {
|
|
127
128
|
className: "p-5 sm:p-6",
|
|
@@ -133,10 +134,10 @@ function y({ variant: y = "compact", dismissible: b = !0, dismissKey: x = "vibec
|
|
|
133
134
|
children: /* @__PURE__ */ h(c, { className: "size-5 text-accent-purple" })
|
|
134
135
|
}), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("h3", {
|
|
135
136
|
className: "text-base font-semibold text-text-primary",
|
|
136
|
-
children:
|
|
137
|
+
children: w("vibecontrols.shared.agentSetupBanner.title", "Get Started with VibeControls Agent")
|
|
137
138
|
}), /* @__PURE__ */ h("p", {
|
|
138
139
|
className: "text-sm text-text-secondary mt-0.5",
|
|
139
|
-
children:
|
|
140
|
+
children: w("vibecontrols.shared.agentSetupBanner.description", "Install the CLI on any machine you want to manage. The only prerequisite is bun — the curl script installs it for you.")
|
|
140
141
|
})] })]
|
|
141
142
|
}),
|
|
142
143
|
/* @__PURE__ */ h("div", {
|
|
@@ -145,17 +146,21 @@ function y({ variant: y = "compact", dismissible: b = !0, dismissKey: x = "vibec
|
|
|
145
146
|
}),
|
|
146
147
|
/* @__PURE__ */ g("div", {
|
|
147
148
|
className: "flex flex-wrap items-center gap-3 mt-5 ml-0 sm:ml-13",
|
|
148
|
-
children: [/* @__PURE__ */ g(
|
|
149
|
-
|
|
150
|
-
onClick: () =>
|
|
151
|
-
className: "
|
|
152
|
-
children: [
|
|
153
|
-
}), /* @__PURE__ */
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
149
|
+
children: [/* @__PURE__ */ g(_, {
|
|
150
|
+
variant: "default",
|
|
151
|
+
onClick: () => T("/getting-started"),
|
|
152
|
+
className: "gap-2",
|
|
153
|
+
children: [w("vibecontrols.shared.agentSetupBanner.viewFullSetupGuide", "View full setup guide"), /* @__PURE__ */ h(l, { className: "size-3.5" })]
|
|
154
|
+
}), /* @__PURE__ */ h(_, {
|
|
155
|
+
variant: "outline",
|
|
156
|
+
asChild: !0,
|
|
157
|
+
className: "gap-2",
|
|
158
|
+
children: /* @__PURE__ */ g("a", {
|
|
159
|
+
href: v,
|
|
160
|
+
target: "_blank",
|
|
161
|
+
rel: "noopener noreferrer",
|
|
162
|
+
children: [w("vibecontrols.shared.agentSetupBanner.npmPackage", "npm package"), /* @__PURE__ */ h(l, { className: "size-3.5" })]
|
|
163
|
+
})
|
|
159
164
|
})]
|
|
160
165
|
})
|
|
161
166
|
]
|
|
@@ -163,6 +168,6 @@ function y({ variant: y = "compact", dismissible: b = !0, dismissKey: x = "vibec
|
|
|
163
168
|
}) });
|
|
164
169
|
}
|
|
165
170
|
//#endregion
|
|
166
|
-
export {
|
|
171
|
+
export { b as AgentSetupBanner };
|
|
167
172
|
|
|
168
173
|
//# sourceMappingURL=AgentSetupBanner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentSetupBanner.js","names":[],"sources":["../../../src/components/shared/AgentSetupBanner.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { Download, Copy, Check, ExternalLink, X, Terminal } from 'lucide-react';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { getProfileScopedKey } from '@burdenoff/fe-libs/shared/utils';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { InstallTabs } from './InstallTabs';\n\ninterface AgentSetupBannerProps {\n /** Compact mode shows a single-line banner; full mode shows a multi-step card */\n variant?: 'compact' | 'full';\n /** Allow the banner to be dismissed */\n dismissible?: boolean;\n /** Storage key for dismissed state */\n dismissKey?: string;\n /** Additional CSS class names */\n className?: string;\n}\n\nconst NPM_URL = 'https://www.npmjs.com/package/@vibecontrols/agent';\n\n/**\n * Build the quick-install one-liner using the live host so the command shown\n * to the user reflects the environment they are actually on (local dev,\n * alpha, prod). InstallTabs uses the same `resolveHost()` shape — keep them\n * aligned by reading from `window.__VIBECONTROLS_HOST__` first, then\n * falling back to `window.location.host`.\n */\nfunction getQuickInstallCommand(): string {\n if (typeof window === 'undefined') {\n return 'curl -fsSL https://app.vibecontrols.com/install | bash';\n }\n const injected = (window as { __VIBECONTROLS_HOST__?: string }).__VIBECONTROLS_HOST__;\n const host = injected ?? window.location.host;\n return `curl -fsSL https://${host}/install | bash`;\n}\n\n/**\n * Reusable banner/card prompting users to install the VibeControls Agent CLI.\n * Used across multiple pages (Overview, Agents, Sessions, Tunnels, SSH, etc.)\n *\n * The full variant mirrors the Getting Started page's tabbed install widget\n * (`InstallTabs`) so users see a single consistent install flow wherever\n * the banner shows up.\n */\nexport function AgentSetupBanner({\n variant = 'compact',\n dismissible = true,\n dismissKey = 'vibecontrols-setup-banner-dismissed',\n className = '',\n}: AgentSetupBannerProps) {\n const tr = useTr();\n const handleNavigate = useVibeNavigate();\n const quickInstall = useMemo(() => getQuickInstallCommand(), []);\n const [copied, setCopied] = useState(false);\n const [dismissed, setDismissed] = useState(() => {\n try {\n return localStorage.getItem(getProfileScopedKey(dismissKey)) === 'true';\n } catch {\n return false;\n }\n });\n\n const handleCopy = useCallback(async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch {\n const el = document.createElement('textarea');\n el.value = text;\n document.body.appendChild(el);\n el.select();\n document.execCommand('copy');\n document.body.removeChild(el);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }\n }, []);\n\n const handleDismiss = useCallback(() => {\n setDismissed(true);\n try {\n localStorage.setItem(getProfileScopedKey(dismissKey), 'true');\n } catch {\n // ignore\n }\n }, [dismissKey]);\n\n const bannerTransition = { duration: 0.3, ease: [0.4, 0, 0.2, 1] as const };\n\n // ─── Compact variant: single-line info banner ─────────────────────────\n if (variant === 'compact') {\n return (\n <AnimatePresence>\n {!dismissed && (\n <motion.div\n initial={{ opacity: 0, y: -8, height: 0 }}\n animate={{ opacity: 1, y: 0, height: 'auto' }}\n exit={{ opacity: 0, y: -8, height: 0 }}\n transition={bannerTransition}\n className={`relative flex flex-col items-start gap-3 px-4 py-3 bg-accent-purple-subtle border border-accent-purple/20 rounded-lg sm:flex-row sm:items-center ${className}`}\n >\n <Download className=\"size-5 text-accent-purple flex-shrink-0\" />\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-x-3 gap-y-1\">\n <span className=\"text-sm font-medium text-text-primary\">\n {tr(\n 'vibecontrols.shared.agentSetupBanner.installPrompt',\n 'Install the VibeControls Agent CLI to get started'\n )}\n </span>\n <code\n className=\"inline-flex min-w-0 max-w-full items-center gap-1.5 rounded border border-border-default bg-bg-sunken px-2.5 py-1 font-mono text-xs text-text-primary transition-colors hover:bg-bg-elevated\"\n onClick={() => handleCopy(quickInstall)}\n title={tr('vibecontrols.shared.agentSetupBanner.clickToCopy', 'Click to copy')}\n >\n <Terminal className=\"size-3\" />\n <span className=\"min-w-0 break-all\">{quickInstall}</span>\n {copied ? (\n <Check className=\"size-3 text-status-success-text\" />\n ) : (\n <Copy className=\"size-3 text-text-muted\" />\n )}\n </code>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/getting-started')}\n className=\"text-sm text-accent-purple hover:underline flex items-center gap-1\"\n >\n {tr('vibecontrols.shared.agentSetupBanner.setupGuide', 'Setup guide')}{' '}\n <ExternalLink className=\"size-3\" />\n </button>\n </div>\n {dismissible && (\n <button\n type=\"button\"\n onClick={handleDismiss}\n className=\"flex-shrink-0 p-1 text-text-muted hover:text-text-secondary rounded transition-colors\"\n title={tr('vibecontrols.shared.agentSetupBanner.dismiss', 'Dismiss')}\n >\n <X className=\"size-4\" />\n </button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n );\n }\n\n // ─── Full variant: tabbed install card (mirrors Getting Started) ──────\n return (\n <AnimatePresence>\n {!dismissed && (\n <motion.div\n initial={{ opacity: 0, y: -8, height: 0 }}\n animate={{ opacity: 1, y: 0, height: 'auto' }}\n exit={{ opacity: 0, y: -8, height: 0 }}\n transition={bannerTransition}\n className={`relative border border-accent-purple/20 bg-accent-purple-subtle rounded-lg overflow-hidden ${className}`}\n >\n {dismissible && (\n <button\n type=\"button\"\n onClick={handleDismiss}\n className=\"absolute top-3 right-3 p-1 text-text-muted hover:text-text-secondary rounded transition-colors z-10\"\n title={tr('vibecontrols.shared.agentSetupBanner.dismiss', 'Dismiss')}\n >\n <X className=\"size-4\" />\n </button>\n )}\n\n <div className=\"p-5 sm:p-6\">\n <div className=\"flex items-start gap-3 mb-4\">\n <div className=\"flex-shrink-0 size-10 rounded-lg bg-accent-purple/10 flex items-center justify-center\">\n <Download className=\"size-5 text-accent-purple\" />\n </div>\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr(\n 'vibecontrols.shared.agentSetupBanner.title',\n 'Get Started with VibeControls Agent'\n )}\n </h3>\n <p className=\"text-sm text-text-secondary mt-0.5\">\n {tr(\n 'vibecontrols.shared.agentSetupBanner.description',\n 'Install the CLI on any machine you want to manage. The only prerequisite is bun — the curl script installs it for you.'\n )}\n </p>\n </div>\n </div>\n\n {/* Tabbed install widget mirrors the Getting Started page */}\n <div className=\"ml-0 sm:ml-13\">\n <InstallTabs compact />\n </div>\n\n {/* Actions */}\n <div className=\"flex flex-wrap items-center gap-3 mt-5 ml-0 sm:ml-13\">\n <button\n type=\"button\"\n onClick={() => handleNavigate('/getting-started')}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm bg-accent-purple text-text-inverse rounded-md hover:bg-accent-purple/90 transition-colors\"\n >\n {tr(\n 'vibecontrols.shared.agentSetupBanner.viewFullSetupGuide',\n 'View full setup guide'\n )}\n <ExternalLink className=\"size-3.5\" />\n </button>\n <a\n href={NPM_URL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm border border-border-default text-text-primary rounded-md hover:bg-bg-sunken transition-colors\"\n >\n {tr('vibecontrols.shared.agentSetupBanner.npmPackage', 'npm package')}\n <ExternalLink className=\"size-3.5\" />\n </a>\n </div>\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AgentSetupBanner.js","names":[],"sources":["../../../src/components/shared/AgentSetupBanner.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { Download, Copy, Check, ExternalLink, X, Terminal } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { getProfileScopedKey } from '@burdenoff/fe-libs/shared/utils';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { InstallTabs } from './InstallTabs';\n\ninterface AgentSetupBannerProps {\n /** Compact mode shows a single-line banner; full mode shows a multi-step card */\n variant?: 'compact' | 'full';\n /** Allow the banner to be dismissed */\n dismissible?: boolean;\n /** Storage key for dismissed state */\n dismissKey?: string;\n /** Additional CSS class names */\n className?: string;\n}\n\nconst NPM_URL = 'https://www.npmjs.com/package/@vibecontrols/agent';\n\n/**\n * Build the quick-install one-liner using the live host so the command shown\n * to the user reflects the environment they are actually on (local dev,\n * alpha, prod). InstallTabs uses the same `resolveHost()` shape — keep them\n * aligned by reading from `window.__VIBECONTROLS_HOST__` first, then\n * falling back to `window.location.host`.\n */\nfunction getQuickInstallCommand(): string {\n if (typeof window === 'undefined') {\n return 'curl -fsSL https://app.vibecontrols.com/install | bash';\n }\n const injected = (window as { __VIBECONTROLS_HOST__?: string }).__VIBECONTROLS_HOST__;\n const host = injected ?? window.location.host;\n return `curl -fsSL https://${host}/install | bash`;\n}\n\n/**\n * Reusable banner/card prompting users to install the VibeControls Agent CLI.\n * Used across multiple pages (Overview, Agents, Sessions, Tunnels, SSH, etc.)\n *\n * The full variant mirrors the Getting Started page's tabbed install widget\n * (`InstallTabs`) so users see a single consistent install flow wherever\n * the banner shows up.\n */\nexport function AgentSetupBanner({\n variant = 'compact',\n dismissible = true,\n dismissKey = 'vibecontrols-setup-banner-dismissed',\n className = '',\n}: AgentSetupBannerProps) {\n const tr = useTr();\n const handleNavigate = useVibeNavigate();\n const quickInstall = useMemo(() => getQuickInstallCommand(), []);\n const [copied, setCopied] = useState(false);\n const [dismissed, setDismissed] = useState(() => {\n try {\n return localStorage.getItem(getProfileScopedKey(dismissKey)) === 'true';\n } catch {\n return false;\n }\n });\n\n const handleCopy = useCallback(async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch {\n const el = document.createElement('textarea');\n el.value = text;\n document.body.appendChild(el);\n el.select();\n document.execCommand('copy');\n document.body.removeChild(el);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }\n }, []);\n\n const handleDismiss = useCallback(() => {\n setDismissed(true);\n try {\n localStorage.setItem(getProfileScopedKey(dismissKey), 'true');\n } catch {\n // ignore\n }\n }, [dismissKey]);\n\n const bannerTransition = { duration: 0.3, ease: [0.4, 0, 0.2, 1] as const };\n\n // ─── Compact variant: single-line info banner ─────────────────────────\n if (variant === 'compact') {\n return (\n <AnimatePresence>\n {!dismissed && (\n <motion.div\n initial={{ opacity: 0, y: -8, height: 0 }}\n animate={{ opacity: 1, y: 0, height: 'auto' }}\n exit={{ opacity: 0, y: -8, height: 0 }}\n transition={bannerTransition}\n className={`relative flex flex-col items-start gap-3 px-4 py-3 bg-accent-purple-subtle border border-accent-purple/20 rounded-lg sm:flex-row sm:items-center ${className}`}\n >\n <Download className=\"size-5 text-accent-purple flex-shrink-0\" />\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-x-3 gap-y-1\">\n <span className=\"text-sm font-medium text-text-primary\">\n {tr(\n 'vibecontrols.shared.agentSetupBanner.installPrompt',\n 'Install the VibeControls Agent CLI to get started'\n )}\n </span>\n <code\n className=\"inline-flex min-w-0 max-w-full items-center gap-1.5 rounded border border-border-default bg-bg-sunken px-2.5 py-1 font-mono text-xs text-text-primary transition-colors hover:bg-bg-elevated\"\n onClick={() => handleCopy(quickInstall)}\n title={tr('vibecontrols.shared.agentSetupBanner.clickToCopy', 'Click to copy')}\n >\n <Terminal className=\"size-3\" />\n <span className=\"min-w-0 break-all\">{quickInstall}</span>\n {copied ? (\n <Check className=\"size-3 text-status-success-text\" />\n ) : (\n <Copy className=\"size-3 text-text-muted\" />\n )}\n </code>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/getting-started')}\n className=\"text-sm text-accent-purple hover:underline flex items-center gap-1\"\n >\n {tr('vibecontrols.shared.agentSetupBanner.setupGuide', 'Setup guide')}{' '}\n <ExternalLink className=\"size-3\" />\n </button>\n </div>\n {dismissible && (\n <button\n type=\"button\"\n onClick={handleDismiss}\n className=\"flex-shrink-0 p-1 text-text-muted hover:text-text-secondary rounded transition-colors\"\n title={tr('vibecontrols.shared.agentSetupBanner.dismiss', 'Dismiss')}\n >\n <X className=\"size-4\" />\n </button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n );\n }\n\n // ─── Full variant: tabbed install card (mirrors Getting Started) ──────\n return (\n <AnimatePresence>\n {!dismissed && (\n <motion.div\n initial={{ opacity: 0, y: -8, height: 0 }}\n animate={{ opacity: 1, y: 0, height: 'auto' }}\n exit={{ opacity: 0, y: -8, height: 0 }}\n transition={bannerTransition}\n className={`relative border border-accent-purple/20 bg-accent-purple-subtle rounded-lg overflow-hidden ${className}`}\n >\n {dismissible && (\n <button\n type=\"button\"\n onClick={handleDismiss}\n className=\"absolute top-3 right-3 p-1 text-text-muted hover:text-text-secondary rounded transition-colors z-10\"\n title={tr('vibecontrols.shared.agentSetupBanner.dismiss', 'Dismiss')}\n >\n <X className=\"size-4\" />\n </button>\n )}\n\n <div className=\"p-5 sm:p-6\">\n <div className=\"flex items-start gap-3 mb-4\">\n <div className=\"flex-shrink-0 size-10 rounded-lg bg-accent-purple/10 flex items-center justify-center\">\n <Download className=\"size-5 text-accent-purple\" />\n </div>\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr(\n 'vibecontrols.shared.agentSetupBanner.title',\n 'Get Started with VibeControls Agent'\n )}\n </h3>\n <p className=\"text-sm text-text-secondary mt-0.5\">\n {tr(\n 'vibecontrols.shared.agentSetupBanner.description',\n 'Install the CLI on any machine you want to manage. The only prerequisite is bun — the curl script installs it for you.'\n )}\n </p>\n </div>\n </div>\n\n {/* Tabbed install widget mirrors the Getting Started page */}\n <div className=\"ml-0 sm:ml-13\">\n <InstallTabs compact />\n </div>\n\n {/* Actions */}\n <div className=\"flex flex-wrap items-center gap-3 mt-5 ml-0 sm:ml-13\">\n <Button\n variant=\"default\"\n onClick={() => handleNavigate('/getting-started')}\n className=\"gap-2\"\n >\n {tr(\n 'vibecontrols.shared.agentSetupBanner.viewFullSetupGuide',\n 'View full setup guide'\n )}\n <ExternalLink className=\"size-3.5\" />\n </Button>\n <Button variant=\"outline\" asChild className=\"gap-2\">\n <a href={NPM_URL} target=\"_blank\" rel=\"noopener noreferrer\">\n {tr('vibecontrols.shared.agentSetupBanner.npmPackage', 'npm package')}\n <ExternalLink className=\"size-3.5\" />\n </a>\n </Button>\n </div>\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n );\n}\n"],"mappings":"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"}
|