@burdenoff/microfe-vibecontrols 2026.513.1 → 2026.514.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,223 +1,214 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SearchableSelect as t } from "../shared/SearchableSelect.js";
|
|
1
|
+
import { SearchableSelect as e } from "../shared/SearchableSelect.js";
|
|
3
2
|
import "../shared/index.js";
|
|
4
|
-
import { useCallback as
|
|
5
|
-
import { useI18n as
|
|
6
|
-
import { Check as
|
|
7
|
-
import { Fragment as
|
|
3
|
+
import { useCallback as t, useState as n } from "react";
|
|
4
|
+
import { useI18n as r } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
5
|
+
import { Check as i, CheckCircle2 as a, ChevronDown as o, ChevronLeft as ee, ChevronRight as s, Copy as te, Download as ne, Eye as re, EyeOff as ie, Loader2 as c, Plus as l, RefreshCw as u, Settings2 as ae, Terminal as oe, X as se, XCircle as d } from "lucide-react";
|
|
6
|
+
import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
8
7
|
//#region src/components/agents/AgentForm.tsx
|
|
9
|
-
function
|
|
10
|
-
let { t:
|
|
11
|
-
let n =
|
|
8
|
+
function h({ onSubmit: h, onCancel: g, isLoading: _, onNavigate: v, targets: y, targetsLoading: ce, onCreateTarget: b }) {
|
|
9
|
+
let { t: le } = r(), x = (e, t) => {
|
|
10
|
+
let n = le(e);
|
|
12
11
|
return n === e ? t : n;
|
|
13
|
-
}, [
|
|
14
|
-
navigator.clipboard.writeText(e),
|
|
15
|
-
}, []),
|
|
12
|
+
}, [S, C] = n("details"), [w, ue] = n(!1), [T, de] = n(!1), [fe, pe] = n(null), [E, me] = n(""), [D, O] = n(""), [k, A] = n(""), [j, M] = n(""), [N, P] = n(!1), [F, I] = n(""), [L, R] = n(!1), [z, B] = n(null), [V, H] = n(!1), [U, W] = n(null), [G, K] = n(null), [q, he] = n(""), [J, ge] = n("linux"), [_e, ve] = n("x86_64"), [ye, be] = n("1.0.0"), [xe, Y] = n(null), [X, Se] = n(!1), [Ce, we] = n("default"), Te = t((e, t) => {
|
|
13
|
+
navigator.clipboard.writeText(e), pe(t), setTimeout(() => pe(null), 2e3);
|
|
14
|
+
}, []), Ee = (e) => {
|
|
16
15
|
let t = e.trim();
|
|
17
16
|
return t.endsWith("/") && (t = t.slice(0, -1)), t;
|
|
18
|
-
},
|
|
19
|
-
let e =
|
|
20
|
-
|
|
21
|
-
L(!0), z(null), V(null);
|
|
17
|
+
}, De = async () => {
|
|
18
|
+
let e = Ee(D);
|
|
19
|
+
e && (H(!0), W(null), K(null), await Promise.all([(async () => {
|
|
22
20
|
try {
|
|
23
|
-
let
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} });
|
|
27
|
-
if (n) {
|
|
28
|
-
z({
|
|
21
|
+
let t = await fetch(`${e}/health`, { signal: AbortSignal.timeout(1e4) });
|
|
22
|
+
if (!t.ok) {
|
|
23
|
+
W({
|
|
29
24
|
ok: !1,
|
|
30
|
-
error:
|
|
31
|
-
})
|
|
32
|
-
ok: !1,
|
|
33
|
-
error: n.message
|
|
34
|
-
}), L(!1);
|
|
25
|
+
error: `HTTP ${String(t.status)}: ${t.statusText}`
|
|
26
|
+
});
|
|
35
27
|
return;
|
|
36
28
|
}
|
|
37
|
-
let
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
29
|
+
let n = await t.json();
|
|
30
|
+
W({
|
|
31
|
+
ok: !0,
|
|
32
|
+
data: {
|
|
33
|
+
status: n.status || "healthy",
|
|
34
|
+
version: n.version || "unknown",
|
|
35
|
+
uptime: n.uptime || 0
|
|
36
|
+
}
|
|
37
|
+
}), n.version && be(n.version);
|
|
38
|
+
} catch (e) {
|
|
39
|
+
W({
|
|
40
|
+
ok: !1,
|
|
41
|
+
error: e instanceof DOMException && e.name === "AbortError" ? "Health check timed out after 10s" : e instanceof Error ? e.message : "Health check failed"
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
})(), (async () => {
|
|
45
|
+
try {
|
|
46
|
+
let t = {};
|
|
47
|
+
k && (t["x-agent-api-key"] = k);
|
|
48
|
+
let n = await fetch(`${e}/api/profiles/default/agent/identity`, {
|
|
49
|
+
headers: t,
|
|
50
|
+
signal: AbortSignal.timeout(1e4)
|
|
51
|
+
});
|
|
52
|
+
if (!n.ok) {
|
|
53
|
+
K({
|
|
43
54
|
ok: !1,
|
|
44
|
-
error: "
|
|
45
|
-
})
|
|
55
|
+
error: n.status === 401 ? "Invalid API key" : `HTTP ${String(n.status)}: ${n.statusText}`
|
|
56
|
+
});
|
|
46
57
|
return;
|
|
47
58
|
}
|
|
48
|
-
|
|
59
|
+
let r = await n.json(), i = r.hostname || "", a = r.platform || "linux", o = r.arch || "x86_64";
|
|
60
|
+
K({
|
|
49
61
|
ok: !0,
|
|
50
62
|
data: {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
63
|
+
hostname: i,
|
|
64
|
+
platform: a,
|
|
65
|
+
arch: o
|
|
54
66
|
}
|
|
55
|
-
}),
|
|
56
|
-
ok: !1,
|
|
57
|
-
error: r.healthError || "Health check failed"
|
|
58
|
-
}), r.identityOk) {
|
|
59
|
-
let e = r.hostname || "", t = r.platform || "linux", n = r.architecture || "x86_64";
|
|
60
|
-
V({
|
|
61
|
-
ok: !0,
|
|
62
|
-
data: {
|
|
63
|
-
hostname: e,
|
|
64
|
-
platform: t,
|
|
65
|
-
arch: n
|
|
66
|
-
}
|
|
67
|
-
}), e && xe(e), t && W(t), n && K(n), !C && e && ve(e);
|
|
68
|
-
} else V({
|
|
69
|
-
ok: !1,
|
|
70
|
-
error: r.identityError || "Identity check failed"
|
|
71
|
-
});
|
|
67
|
+
}), i && he(i), a && ge(a), o && ve(o), !E && i && me(i);
|
|
72
68
|
} catch (e) {
|
|
73
|
-
|
|
74
|
-
z({
|
|
69
|
+
K({
|
|
75
70
|
ok: !1,
|
|
76
|
-
error:
|
|
77
|
-
}), V({
|
|
78
|
-
ok: !1,
|
|
79
|
-
error: t
|
|
71
|
+
error: e instanceof DOMException && e.name === "AbortError" ? "Identity check timed out after 10s" : e instanceof Error ? e.message : "Identity check failed"
|
|
80
72
|
});
|
|
81
73
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
tunnelUrl: Oe(w),
|
|
74
|
+
})()]), H(!1));
|
|
75
|
+
}, Oe = async () => {
|
|
76
|
+
Y(null);
|
|
77
|
+
let e = Ce.trim() || "default", t = {
|
|
78
|
+
name: E || q || "Unnamed Agent",
|
|
79
|
+
hostname: q || "unknown",
|
|
80
|
+
platform: J,
|
|
81
|
+
architecture: _e,
|
|
82
|
+
version: ye,
|
|
83
|
+
tunnelUrl: Ee(D),
|
|
93
84
|
tunnelStatus: "ACTIVE",
|
|
94
|
-
agentApiKey:
|
|
85
|
+
agentApiKey: k,
|
|
95
86
|
metadata: { profile: e },
|
|
96
|
-
...
|
|
87
|
+
...j ? { targetId: j } : {}
|
|
97
88
|
};
|
|
98
89
|
try {
|
|
99
|
-
let e = (await
|
|
90
|
+
let e = (await h(t))?.id || null;
|
|
100
91
|
if (!e) {
|
|
101
|
-
|
|
92
|
+
Y("Agent creation returned no ID. The agent may already exist.");
|
|
102
93
|
return;
|
|
103
94
|
}
|
|
104
|
-
|
|
95
|
+
v ? v(`/agents/${e}`) : g();
|
|
105
96
|
} catch (e) {
|
|
106
|
-
|
|
97
|
+
Y(e instanceof Error ? e.message : "Failed to create agent");
|
|
107
98
|
}
|
|
108
|
-
},
|
|
109
|
-
if (!(!
|
|
110
|
-
|
|
99
|
+
}, ke = U?.ok && G?.ok, Z = y && y.length > 0, Ae = (b || Z) && j.length === 0, je = D.trim().length > 0 && !Ae, Me = t(async () => {
|
|
100
|
+
if (!(!b || !F.trim())) {
|
|
101
|
+
R(!0), B(null);
|
|
111
102
|
try {
|
|
112
|
-
let e = await
|
|
113
|
-
e ? (
|
|
103
|
+
let e = await b(F.trim());
|
|
104
|
+
e ? (M(e.id), P(!1), I("")) : B(x("agentsPage.inlineTargetFailed", "Failed to create target. Please try again."));
|
|
114
105
|
} catch (e) {
|
|
115
|
-
|
|
106
|
+
B(e instanceof Error ? e.message : "Failed to create target");
|
|
116
107
|
} finally {
|
|
117
|
-
|
|
108
|
+
R(!1);
|
|
118
109
|
}
|
|
119
110
|
}
|
|
120
111
|
}, [
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
]),
|
|
112
|
+
b,
|
|
113
|
+
F,
|
|
114
|
+
x
|
|
115
|
+
]), Ne = ({ text: e, id: t }) => /* @__PURE__ */ p("button", {
|
|
125
116
|
type: "button",
|
|
126
|
-
onClick: () =>
|
|
117
|
+
onClick: () => Te(e, t),
|
|
127
118
|
className: "p-1 rounded hover:bg-bg-elevated transition-colors",
|
|
128
|
-
title:
|
|
129
|
-
children:
|
|
119
|
+
title: x("agentsPage.copy", "Copy"),
|
|
120
|
+
children: fe === t ? /* @__PURE__ */ p(i, { className: "w-3.5 h-3.5 text-status-success-text" }) : /* @__PURE__ */ p(te, { className: "w-3.5 h-3.5 text-text-secondary" })
|
|
130
121
|
}), Q = [{
|
|
131
122
|
key: "details",
|
|
132
123
|
label: "Setup"
|
|
133
124
|
}, {
|
|
134
125
|
key: "validate",
|
|
135
126
|
label: "Validate"
|
|
136
|
-
}], $ = Q.findIndex((e) => e.key ===
|
|
137
|
-
return /* @__PURE__ */
|
|
127
|
+
}], $ = Q.findIndex((e) => e.key === S);
|
|
128
|
+
return /* @__PURE__ */ p("div", {
|
|
138
129
|
className: "fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay",
|
|
139
|
-
children: /* @__PURE__ */
|
|
130
|
+
children: /* @__PURE__ */ m("div", {
|
|
140
131
|
className: "w-full max-w-xl bg-bg-surface rounded-lg shadow-xl max-h-[90vh] overflow-y-auto",
|
|
141
132
|
children: [
|
|
142
|
-
/* @__PURE__ */
|
|
133
|
+
/* @__PURE__ */ m("div", {
|
|
143
134
|
className: "flex items-center justify-between px-6 py-4 border-b border-border-default sticky top-0 bg-bg-surface z-10",
|
|
144
|
-
children: [/* @__PURE__ */
|
|
135
|
+
children: [/* @__PURE__ */ p("h2", {
|
|
145
136
|
className: "text-lg font-semibold text-text-primary",
|
|
146
|
-
children:
|
|
147
|
-
}), /* @__PURE__ */
|
|
148
|
-
onClick:
|
|
137
|
+
children: x("agentsPage.addNewAgent", "Add New Agent")
|
|
138
|
+
}), /* @__PURE__ */ p("button", {
|
|
139
|
+
onClick: g,
|
|
149
140
|
className: "p-1 rounded hover:bg-bg-sunken transition-colors",
|
|
150
|
-
children: /* @__PURE__ */
|
|
141
|
+
children: /* @__PURE__ */ p(se, { className: "w-5 h-5 text-text-secondary" })
|
|
151
142
|
})]
|
|
152
143
|
}),
|
|
153
|
-
/* @__PURE__ */
|
|
144
|
+
/* @__PURE__ */ p("div", {
|
|
154
145
|
className: "flex items-center gap-2 px-6 pt-4 pb-2",
|
|
155
|
-
children: Q.map((e, t) => /* @__PURE__ */
|
|
146
|
+
children: Q.map((e, t) => /* @__PURE__ */ m("div", {
|
|
156
147
|
className: "flex items-center gap-2",
|
|
157
148
|
children: [
|
|
158
|
-
/* @__PURE__ */
|
|
149
|
+
/* @__PURE__ */ p("div", {
|
|
159
150
|
className: `flex items-center justify-center w-7 h-7 rounded-full text-xs font-semibold transition-colors ${t < $ ? "bg-status-success-bg text-status-success-text" : t === $ ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary"}`,
|
|
160
|
-
children: t < $ ? /* @__PURE__ */
|
|
151
|
+
children: t < $ ? /* @__PURE__ */ p(a, { className: "w-4 h-4" }) : t + 1
|
|
161
152
|
}),
|
|
162
|
-
/* @__PURE__ */
|
|
153
|
+
/* @__PURE__ */ p("span", {
|
|
163
154
|
className: `text-sm ${t === $ ? "font-medium text-text-primary" : "text-text-secondary"}`,
|
|
164
155
|
children: e.label
|
|
165
156
|
}),
|
|
166
|
-
t < Q.length - 1 && /* @__PURE__ */
|
|
157
|
+
t < Q.length - 1 && /* @__PURE__ */ p(s, { className: "w-4 h-4 text-text-muted" })
|
|
167
158
|
]
|
|
168
159
|
}, e.key))
|
|
169
160
|
}),
|
|
170
|
-
/* @__PURE__ */
|
|
161
|
+
/* @__PURE__ */ m("div", {
|
|
171
162
|
className: "p-6",
|
|
172
|
-
children: [
|
|
163
|
+
children: [S === "details" && /* @__PURE__ */ m("div", {
|
|
173
164
|
className: "space-y-4",
|
|
174
165
|
children: [
|
|
175
|
-
/* @__PURE__ */
|
|
166
|
+
/* @__PURE__ */ m("div", {
|
|
176
167
|
className: "border border-border-default rounded-lg overflow-hidden",
|
|
177
|
-
children: [/* @__PURE__ */
|
|
168
|
+
children: [/* @__PURE__ */ m("button", {
|
|
178
169
|
type: "button",
|
|
179
|
-
onClick: () =>
|
|
170
|
+
onClick: () => de(!T),
|
|
180
171
|
className: "w-full flex items-center justify-between px-4 py-3 bg-bg-sunken hover:bg-bg-sunken/80 transition-colors",
|
|
181
|
-
children: [/* @__PURE__ */
|
|
172
|
+
children: [/* @__PURE__ */ m("div", {
|
|
182
173
|
className: "flex items-center gap-2",
|
|
183
|
-
children: [/* @__PURE__ */
|
|
174
|
+
children: [/* @__PURE__ */ p(ne, { className: "w-4 h-4 text-action-primary-bg" }), /* @__PURE__ */ p("span", {
|
|
184
175
|
className: "text-sm font-medium text-text-primary",
|
|
185
|
-
children:
|
|
176
|
+
children: x("agentsPage.installInstructions", "Agent Install Instructions")
|
|
186
177
|
})]
|
|
187
|
-
}), /* @__PURE__ */
|
|
188
|
-
}),
|
|
178
|
+
}), /* @__PURE__ */ p(s, { className: `w-4 h-4 text-text-secondary transition-transform ${T ? "rotate-90" : ""}` })]
|
|
179
|
+
}), T && /* @__PURE__ */ p("div", {
|
|
189
180
|
className: "px-4 py-3 space-y-3 border-t border-border-default",
|
|
190
|
-
children: /* @__PURE__ */
|
|
181
|
+
children: /* @__PURE__ */ p("div", {
|
|
191
182
|
className: "space-y-2",
|
|
192
183
|
children: [
|
|
193
184
|
{
|
|
194
|
-
label:
|
|
185
|
+
label: x("agentsPage.installStep1", "1. Install the agent CLI"),
|
|
195
186
|
cmd: "npm install -g @vibecontrols/agent@latest"
|
|
196
187
|
},
|
|
197
188
|
{
|
|
198
|
-
label:
|
|
189
|
+
label: x("agentsPage.installStep2", "2. Start the agent"),
|
|
199
190
|
cmd: "vibe start"
|
|
200
191
|
},
|
|
201
192
|
{
|
|
202
|
-
label:
|
|
193
|
+
label: x("agentsPage.installStep3", "3. Get the API key"),
|
|
203
194
|
cmd: "vibe key"
|
|
204
195
|
},
|
|
205
196
|
{
|
|
206
|
-
label:
|
|
197
|
+
label: x("agentsPage.installStep4", "4. Start the tunnel"),
|
|
207
198
|
cmd: "vibe tunnel agent --start"
|
|
208
199
|
}
|
|
209
|
-
].map((e) => /* @__PURE__ */
|
|
200
|
+
].map((e) => /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
|
|
210
201
|
className: "text-xs text-text-secondary mb-1",
|
|
211
202
|
children: e.label
|
|
212
|
-
}), /* @__PURE__ */
|
|
203
|
+
}), /* @__PURE__ */ m("div", {
|
|
213
204
|
className: "flex items-center gap-2 bg-bg-sunken rounded-md px-3 py-1.5 font-mono text-xs text-text-primary",
|
|
214
205
|
children: [
|
|
215
|
-
/* @__PURE__ */
|
|
216
|
-
/* @__PURE__ */
|
|
206
|
+
/* @__PURE__ */ p(oe, { className: "w-3 h-3 text-text-muted flex-shrink-0" }),
|
|
207
|
+
/* @__PURE__ */ p("code", {
|
|
217
208
|
className: "flex-1",
|
|
218
209
|
children: e.cmd
|
|
219
210
|
}),
|
|
220
|
-
/* @__PURE__ */
|
|
211
|
+
/* @__PURE__ */ p(Ne, {
|
|
221
212
|
text: e.cmd,
|
|
222
213
|
id: e.cmd
|
|
223
214
|
})
|
|
@@ -226,350 +217,350 @@ function fe({ onSubmit: fe, onCancel: f, isLoading: p, onNavigate: m, targets: h
|
|
|
226
217
|
})
|
|
227
218
|
})]
|
|
228
219
|
}),
|
|
229
|
-
/* @__PURE__ */
|
|
230
|
-
/* @__PURE__ */
|
|
220
|
+
/* @__PURE__ */ m("div", { children: [
|
|
221
|
+
/* @__PURE__ */ m("label", {
|
|
231
222
|
className: "block text-sm font-medium text-text-primary mb-1",
|
|
232
223
|
children: [
|
|
233
|
-
|
|
224
|
+
x("agentsPage.target", "Target"),
|
|
234
225
|
" ",
|
|
235
|
-
/* @__PURE__ */
|
|
226
|
+
/* @__PURE__ */ p("span", {
|
|
236
227
|
className: "text-status-error-text",
|
|
237
228
|
children: "*"
|
|
238
229
|
})
|
|
239
230
|
]
|
|
240
231
|
}),
|
|
241
|
-
Z && !
|
|
242
|
-
placeholder:
|
|
243
|
-
searchPlaceholder:
|
|
244
|
-
options: (
|
|
232
|
+
Z && !N && /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(e, {
|
|
233
|
+
placeholder: x("agentsPage.selectTarget", "Select a target..."),
|
|
234
|
+
searchPlaceholder: x("agentsPage.searchTargets", "Search targets..."),
|
|
235
|
+
options: (y ?? []).map((e) => ({
|
|
245
236
|
value: e.id,
|
|
246
237
|
label: e.name,
|
|
247
238
|
description: `${e.type}${e.status ? ` · ${e.status}` : ""}`
|
|
248
239
|
})),
|
|
249
|
-
value:
|
|
250
|
-
onChange:
|
|
240
|
+
value: j,
|
|
241
|
+
onChange: M,
|
|
251
242
|
clearable: !0
|
|
252
|
-
}), /* @__PURE__ */
|
|
243
|
+
}), /* @__PURE__ */ m("p", {
|
|
253
244
|
className: "mt-1 text-xs text-text-muted",
|
|
254
245
|
children: [
|
|
255
|
-
|
|
246
|
+
x("agentsPage.targetDescription", "The target machine this agent will be installed on."),
|
|
256
247
|
" ",
|
|
257
|
-
|
|
248
|
+
b && /* @__PURE__ */ m("button", {
|
|
258
249
|
type: "button",
|
|
259
250
|
onClick: () => {
|
|
260
|
-
|
|
251
|
+
P(!0), I(E.trim() || "");
|
|
261
252
|
},
|
|
262
253
|
className: "text-action-primary-bg hover:underline inline-flex items-center gap-1",
|
|
263
|
-
children: [/* @__PURE__ */
|
|
254
|
+
children: [/* @__PURE__ */ p(l, { className: "w-3 h-3" }), x("agentsPage.createNewTarget", "Create a new target")]
|
|
264
255
|
})
|
|
265
256
|
]
|
|
266
257
|
})] }),
|
|
267
|
-
!Z && !
|
|
258
|
+
!Z && !ce && b && !N && /* @__PURE__ */ m("div", {
|
|
268
259
|
className: "p-3 bg-bg-sunken border border-border-default rounded-lg",
|
|
269
|
-
children: [/* @__PURE__ */
|
|
260
|
+
children: [/* @__PURE__ */ p("p", {
|
|
270
261
|
className: "text-sm text-text-secondary mb-2",
|
|
271
|
-
children:
|
|
272
|
-
}), /* @__PURE__ */
|
|
262
|
+
children: x("agentsPage.noTargetsInlinePrompt", "You don't have any targets yet. Create one now to install this agent on it.")
|
|
263
|
+
}), /* @__PURE__ */ m("button", {
|
|
273
264
|
type: "button",
|
|
274
265
|
onClick: () => {
|
|
275
|
-
|
|
266
|
+
P(!0), I(E.trim() || "");
|
|
276
267
|
},
|
|
277
268
|
className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:opacity-90",
|
|
278
|
-
children: [/* @__PURE__ */
|
|
269
|
+
children: [/* @__PURE__ */ p(l, { className: "w-4 h-4" }), x("agentsPage.createFirstTarget", "Create first target")]
|
|
279
270
|
})]
|
|
280
271
|
}),
|
|
281
|
-
|
|
272
|
+
N && b && /* @__PURE__ */ m("div", {
|
|
282
273
|
className: "p-3 bg-bg-sunken border border-border-default rounded-lg space-y-2",
|
|
283
274
|
children: [
|
|
284
|
-
/* @__PURE__ */
|
|
275
|
+
/* @__PURE__ */ p("p", {
|
|
285
276
|
className: "text-xs font-medium text-text-secondary",
|
|
286
|
-
children:
|
|
277
|
+
children: x("agentsPage.newDirectTarget", "New target (Direct — you can change the type later)")
|
|
287
278
|
}),
|
|
288
|
-
/* @__PURE__ */
|
|
279
|
+
/* @__PURE__ */ p("input", {
|
|
289
280
|
type: "text",
|
|
290
|
-
value:
|
|
291
|
-
onChange: (e) =>
|
|
292
|
-
placeholder:
|
|
281
|
+
value: F,
|
|
282
|
+
onChange: (e) => I(e.target.value),
|
|
283
|
+
placeholder: x("agentsPage.targetName", "Target name"),
|
|
293
284
|
className: "w-full px-3 py-2 text-sm bg-bg-elevated border border-border-default rounded-md text-text-primary placeholder-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
|
|
294
285
|
autoFocus: !0,
|
|
295
286
|
onKeyDown: (e) => {
|
|
296
|
-
e.key === "Enter" && (e.preventDefault(),
|
|
287
|
+
e.key === "Enter" && (e.preventDefault(), Me());
|
|
297
288
|
}
|
|
298
289
|
}),
|
|
299
|
-
|
|
290
|
+
z && /* @__PURE__ */ p("p", {
|
|
300
291
|
className: "text-xs text-status-error-text",
|
|
301
|
-
children:
|
|
292
|
+
children: z
|
|
302
293
|
}),
|
|
303
|
-
/* @__PURE__ */
|
|
294
|
+
/* @__PURE__ */ m("div", {
|
|
304
295
|
className: "flex items-center gap-2",
|
|
305
|
-
children: [/* @__PURE__ */
|
|
296
|
+
children: [/* @__PURE__ */ m("button", {
|
|
306
297
|
type: "button",
|
|
307
|
-
onClick: () => void
|
|
308
|
-
disabled: !
|
|
298
|
+
onClick: () => void Me(),
|
|
299
|
+
disabled: !F.trim() || L,
|
|
309
300
|
className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:opacity-90 disabled:opacity-50",
|
|
310
|
-
children: [
|
|
311
|
-
}), /* @__PURE__ */
|
|
301
|
+
children: [L ? /* @__PURE__ */ p(c, { className: "w-3.5 h-3.5 animate-spin" }) : /* @__PURE__ */ p(i, { className: "w-3.5 h-3.5" }), x("agentsPage.create", "Create")]
|
|
302
|
+
}), /* @__PURE__ */ p("button", {
|
|
312
303
|
type: "button",
|
|
313
304
|
onClick: () => {
|
|
314
|
-
|
|
305
|
+
P(!1), I(""), B(null);
|
|
315
306
|
},
|
|
316
307
|
className: "px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary",
|
|
317
|
-
children:
|
|
308
|
+
children: x("agentsPage.cancel", "Cancel")
|
|
318
309
|
})]
|
|
319
310
|
})
|
|
320
311
|
]
|
|
321
312
|
}),
|
|
322
|
-
|
|
313
|
+
ce && !Z && /* @__PURE__ */ m("div", {
|
|
323
314
|
className: "p-3 bg-bg-sunken border border-border-default rounded-lg flex items-center gap-2 text-sm text-text-secondary",
|
|
324
|
-
children: [/* @__PURE__ */
|
|
315
|
+
children: [/* @__PURE__ */ p(c, { className: "w-4 h-4 animate-spin" }), x("agentsPage.loadingTargets", "Loading targets...")]
|
|
325
316
|
})
|
|
326
317
|
] }),
|
|
327
|
-
/* @__PURE__ */
|
|
328
|
-
/* @__PURE__ */
|
|
318
|
+
/* @__PURE__ */ m("div", { children: [
|
|
319
|
+
/* @__PURE__ */ m("label", {
|
|
329
320
|
className: "block text-sm font-medium text-text-primary mb-1",
|
|
330
321
|
children: [
|
|
331
|
-
|
|
322
|
+
x("agentsPage.apiTunnelUrl", "API / Tunnel URL"),
|
|
332
323
|
" ",
|
|
333
|
-
/* @__PURE__ */
|
|
324
|
+
/* @__PURE__ */ p("span", {
|
|
334
325
|
className: "text-status-error-text",
|
|
335
326
|
children: "*"
|
|
336
327
|
})
|
|
337
328
|
]
|
|
338
329
|
}),
|
|
339
|
-
/* @__PURE__ */
|
|
330
|
+
/* @__PURE__ */ p("input", {
|
|
340
331
|
type: "url",
|
|
341
|
-
value:
|
|
342
|
-
onChange: (e) =>
|
|
332
|
+
value: D,
|
|
333
|
+
onChange: (e) => O(e.target.value),
|
|
343
334
|
placeholder: "https://your-tunnel.trycloudflare.com",
|
|
344
335
|
required: !0,
|
|
345
336
|
className: "w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono"
|
|
346
337
|
}),
|
|
347
|
-
/* @__PURE__ */
|
|
338
|
+
/* @__PURE__ */ p("p", {
|
|
348
339
|
className: "mt-1 text-xs text-text-muted",
|
|
349
|
-
children:
|
|
340
|
+
children: x("agentsPage.tunnelUrlHint", "The agent's tunnel URL or local API URL (e.g. http://localhost:3005)")
|
|
350
341
|
})
|
|
351
342
|
] }),
|
|
352
|
-
/* @__PURE__ */
|
|
353
|
-
/* @__PURE__ */
|
|
343
|
+
/* @__PURE__ */ m("div", { children: [
|
|
344
|
+
/* @__PURE__ */ m("label", {
|
|
354
345
|
className: "block text-sm font-medium text-text-primary mb-1",
|
|
355
346
|
children: [
|
|
356
|
-
|
|
347
|
+
x("agentsPage.agentApiKey", "Agent API Key"),
|
|
357
348
|
" ",
|
|
358
|
-
/* @__PURE__ */
|
|
349
|
+
/* @__PURE__ */ p("span", {
|
|
359
350
|
className: "text-status-error-text",
|
|
360
351
|
children: "*"
|
|
361
352
|
})
|
|
362
353
|
]
|
|
363
354
|
}),
|
|
364
|
-
/* @__PURE__ */
|
|
355
|
+
/* @__PURE__ */ m("div", {
|
|
365
356
|
className: "relative",
|
|
366
|
-
children: [/* @__PURE__ */
|
|
367
|
-
type:
|
|
368
|
-
value:
|
|
369
|
-
onChange: (e) =>
|
|
357
|
+
children: [/* @__PURE__ */ p("input", {
|
|
358
|
+
type: w ? "text" : "password",
|
|
359
|
+
value: k,
|
|
360
|
+
onChange: (e) => A(e.target.value),
|
|
370
361
|
placeholder: "vcak_...",
|
|
371
362
|
required: !0,
|
|
372
363
|
className: "w-full px-3 py-2 pr-10 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono"
|
|
373
|
-
}), /* @__PURE__ */
|
|
364
|
+
}), /* @__PURE__ */ p("button", {
|
|
374
365
|
type: "button",
|
|
375
|
-
onClick: () =>
|
|
366
|
+
onClick: () => ue(!w),
|
|
376
367
|
className: "absolute right-2 top-1/2 -translate-y-1/2 p-1 rounded hover:bg-bg-elevated transition-colors",
|
|
377
|
-
children:
|
|
368
|
+
children: p(w ? ie : re, { className: "w-4 h-4 text-text-secondary" })
|
|
378
369
|
})]
|
|
379
370
|
}),
|
|
380
|
-
/* @__PURE__ */
|
|
371
|
+
/* @__PURE__ */ m("p", {
|
|
381
372
|
className: "mt-1 text-xs text-text-muted",
|
|
382
373
|
children: [
|
|
383
|
-
|
|
374
|
+
x("agentsPage.apiKeyHint", "Run"),
|
|
384
375
|
" ",
|
|
385
|
-
/* @__PURE__ */
|
|
376
|
+
/* @__PURE__ */ p("code", {
|
|
386
377
|
className: "bg-bg-sunken px-1 rounded",
|
|
387
378
|
children: "vibe key"
|
|
388
379
|
}),
|
|
389
380
|
" ",
|
|
390
|
-
|
|
381
|
+
x("agentsPage.apiKeyHintSuffix", "on the agent to get this. Changes on restart.")
|
|
391
382
|
]
|
|
392
383
|
})
|
|
393
384
|
] }),
|
|
394
|
-
/* @__PURE__ */
|
|
385
|
+
/* @__PURE__ */ m("div", {
|
|
395
386
|
className: "border border-border-default rounded-lg overflow-hidden",
|
|
396
|
-
children: [/* @__PURE__ */
|
|
387
|
+
children: [/* @__PURE__ */ m("button", {
|
|
397
388
|
type: "button",
|
|
398
|
-
onClick: () =>
|
|
389
|
+
onClick: () => Se((e) => !e),
|
|
399
390
|
className: "w-full flex items-center justify-between px-4 py-2.5 bg-bg-sunken hover:bg-bg-sunken/80 transition-colors",
|
|
400
|
-
"aria-expanded":
|
|
391
|
+
"aria-expanded": X,
|
|
401
392
|
"data-testid": "agent-form-advanced-toggle",
|
|
402
|
-
children: [/* @__PURE__ */
|
|
393
|
+
children: [/* @__PURE__ */ m("div", {
|
|
403
394
|
className: "flex items-center gap-2",
|
|
404
|
-
children: [/* @__PURE__ */
|
|
395
|
+
children: [/* @__PURE__ */ p(ae, { className: "w-4 h-4 text-text-secondary" }), /* @__PURE__ */ p("span", {
|
|
405
396
|
className: "text-sm font-medium text-text-primary",
|
|
406
|
-
children:
|
|
397
|
+
children: x("agentsPage.advancedOptions", "Advanced options")
|
|
407
398
|
})]
|
|
408
|
-
}), /* @__PURE__ */
|
|
409
|
-
}),
|
|
399
|
+
}), /* @__PURE__ */ p(o, { className: `w-4 h-4 text-text-secondary transition-transform ${X ? "rotate-180" : ""}` })]
|
|
400
|
+
}), X && /* @__PURE__ */ p("div", {
|
|
410
401
|
className: "px-4 py-3 space-y-3 border-t border-border-default",
|
|
411
|
-
children: /* @__PURE__ */
|
|
412
|
-
/* @__PURE__ */
|
|
402
|
+
children: /* @__PURE__ */ m("div", { children: [
|
|
403
|
+
/* @__PURE__ */ p("label", {
|
|
413
404
|
className: "block text-sm font-medium text-text-primary mb-1",
|
|
414
|
-
children:
|
|
405
|
+
children: x("agentsPage.profileName", "Profile name")
|
|
415
406
|
}),
|
|
416
|
-
/* @__PURE__ */
|
|
407
|
+
/* @__PURE__ */ p("input", {
|
|
417
408
|
type: "text",
|
|
418
|
-
value:
|
|
419
|
-
onChange: (e) =>
|
|
409
|
+
value: Ce,
|
|
410
|
+
onChange: (e) => we(e.target.value),
|
|
420
411
|
placeholder: "default",
|
|
421
412
|
className: "w-full px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono",
|
|
422
413
|
"data-testid": "agent-form-profile-input"
|
|
423
414
|
}),
|
|
424
|
-
/* @__PURE__ */
|
|
415
|
+
/* @__PURE__ */ p("p", {
|
|
425
416
|
className: "mt-1 text-xs text-text-muted",
|
|
426
|
-
children:
|
|
417
|
+
children: x("agentsPage.profileNameHint", "Each profile runs an isolated CLI on the daemon. Leave as \"default\" unless you want this agent to host multiple parallel profiles.")
|
|
427
418
|
})
|
|
428
419
|
] })
|
|
429
420
|
})]
|
|
430
421
|
}),
|
|
431
|
-
/* @__PURE__ */
|
|
422
|
+
/* @__PURE__ */ m("div", {
|
|
432
423
|
className: "flex items-center justify-between pt-4",
|
|
433
|
-
children: [/* @__PURE__ */
|
|
424
|
+
children: [/* @__PURE__ */ p("button", {
|
|
434
425
|
type: "button",
|
|
435
|
-
onClick:
|
|
426
|
+
onClick: g,
|
|
436
427
|
className: "px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors",
|
|
437
|
-
children:
|
|
438
|
-
}), /* @__PURE__ */
|
|
428
|
+
children: x("agentsPage.cancel", "Cancel")
|
|
429
|
+
}), /* @__PURE__ */ m("button", {
|
|
439
430
|
type: "button",
|
|
440
|
-
disabled: !
|
|
431
|
+
disabled: !je,
|
|
441
432
|
onClick: () => {
|
|
442
|
-
|
|
433
|
+
C("validate"), De();
|
|
443
434
|
},
|
|
444
435
|
className: "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 disabled:opacity-50",
|
|
445
|
-
children: [
|
|
436
|
+
children: [x("agentsPage.nextValidate", "Next: Validate"), /* @__PURE__ */ p(s, { className: "w-4 h-4" })]
|
|
446
437
|
})]
|
|
447
438
|
})
|
|
448
439
|
]
|
|
449
|
-
}),
|
|
440
|
+
}), S === "validate" && /* @__PURE__ */ m("div", {
|
|
450
441
|
className: "space-y-4",
|
|
451
442
|
children: [
|
|
452
|
-
/* @__PURE__ */
|
|
443
|
+
/* @__PURE__ */ m("div", {
|
|
453
444
|
className: "space-y-3",
|
|
454
|
-
children: [/* @__PURE__ */
|
|
455
|
-
className: `flex items-center gap-3 p-3 rounded-lg border ${
|
|
456
|
-
children: [
|
|
445
|
+
children: [/* @__PURE__ */ m("div", {
|
|
446
|
+
className: `flex items-center gap-3 p-3 rounded-lg border ${U === null ? "border-border-default bg-bg-sunken" : U.ok ? "border-status-success-text/20 bg-status-success-bg/30" : "border-status-error-text/20 bg-status-error-bg/30"}`,
|
|
447
|
+
children: [V && !U ? /* @__PURE__ */ p(c, { className: "w-5 h-5 text-text-secondary animate-spin" }) : U?.ok ? /* @__PURE__ */ p(a, { className: "w-5 h-5 text-status-success-text" }) : U ? /* @__PURE__ */ p(d, { className: "w-5 h-5 text-status-error-text" }) : /* @__PURE__ */ p("div", { className: "w-5 h-5 rounded-full border-2 border-border-default" }), /* @__PURE__ */ m("div", {
|
|
457
448
|
className: "flex-1",
|
|
458
449
|
children: [
|
|
459
|
-
/* @__PURE__ */
|
|
450
|
+
/* @__PURE__ */ p("p", {
|
|
460
451
|
className: "text-sm font-medium text-text-primary",
|
|
461
|
-
children:
|
|
452
|
+
children: x("agentsPage.healthCheck", "Health Check")
|
|
462
453
|
}),
|
|
463
|
-
|
|
454
|
+
U?.ok && U.data && /* @__PURE__ */ m("p", {
|
|
464
455
|
className: "text-xs text-text-secondary",
|
|
465
456
|
children: [
|
|
466
457
|
"Status: ",
|
|
467
|
-
|
|
458
|
+
U.data.status,
|
|
468
459
|
" | Version: ",
|
|
469
|
-
|
|
460
|
+
U.data.version,
|
|
470
461
|
" | Uptime: ",
|
|
471
|
-
Math.round(
|
|
462
|
+
Math.round(U.data.uptime),
|
|
472
463
|
"s"
|
|
473
464
|
]
|
|
474
465
|
}),
|
|
475
|
-
|
|
466
|
+
U && !U.ok && /* @__PURE__ */ p("p", {
|
|
476
467
|
className: "text-xs text-status-error-text",
|
|
477
|
-
children:
|
|
468
|
+
children: U.error
|
|
478
469
|
})
|
|
479
470
|
]
|
|
480
471
|
})]
|
|
481
|
-
}), /* @__PURE__ */
|
|
482
|
-
className: `flex items-center gap-3 p-3 rounded-lg border ${
|
|
483
|
-
children: [
|
|
472
|
+
}), /* @__PURE__ */ m("div", {
|
|
473
|
+
className: `flex items-center gap-3 p-3 rounded-lg border ${G === null ? "border-border-default bg-bg-sunken" : G.ok ? "border-status-success-text/20 bg-status-success-bg/30" : "border-status-error-text/20 bg-status-error-bg/30"}`,
|
|
474
|
+
children: [V && !G ? /* @__PURE__ */ p(c, { className: "w-5 h-5 text-text-secondary animate-spin" }) : G?.ok ? /* @__PURE__ */ p(a, { className: "w-5 h-5 text-status-success-text" }) : G ? /* @__PURE__ */ p(d, { className: "w-5 h-5 text-status-error-text" }) : /* @__PURE__ */ p("div", { className: "w-5 h-5 rounded-full border-2 border-border-default" }), /* @__PURE__ */ m("div", {
|
|
484
475
|
className: "flex-1",
|
|
485
476
|
children: [
|
|
486
|
-
/* @__PURE__ */
|
|
477
|
+
/* @__PURE__ */ p("p", {
|
|
487
478
|
className: "text-sm font-medium text-text-primary",
|
|
488
|
-
children:
|
|
479
|
+
children: x("agentsPage.apiAccess", "API Access")
|
|
489
480
|
}),
|
|
490
|
-
|
|
481
|
+
G?.ok && G.data && /* @__PURE__ */ m("p", {
|
|
491
482
|
className: "text-xs text-text-secondary",
|
|
492
483
|
children: [
|
|
493
484
|
"Host: ",
|
|
494
|
-
|
|
485
|
+
G.data.hostname,
|
|
495
486
|
" | ",
|
|
496
|
-
|
|
487
|
+
G.data.platform,
|
|
497
488
|
" /",
|
|
498
489
|
" ",
|
|
499
|
-
|
|
490
|
+
G.data.arch
|
|
500
491
|
]
|
|
501
492
|
}),
|
|
502
|
-
|
|
493
|
+
G && !G.ok && /* @__PURE__ */ p("p", {
|
|
503
494
|
className: "text-xs text-status-error-text",
|
|
504
|
-
children:
|
|
495
|
+
children: G.error
|
|
505
496
|
})
|
|
506
497
|
]
|
|
507
498
|
})]
|
|
508
499
|
})]
|
|
509
500
|
}),
|
|
510
|
-
!
|
|
501
|
+
!V && (!U?.ok || !G?.ok) && /* @__PURE__ */ m("button", {
|
|
511
502
|
type: "button",
|
|
512
|
-
onClick:
|
|
503
|
+
onClick: De,
|
|
513
504
|
className: "flex items-center gap-2 px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary hover:bg-bg-sunken rounded-md transition-colors",
|
|
514
|
-
children: [/* @__PURE__ */ u
|
|
505
|
+
children: [/* @__PURE__ */ p(u, { className: "w-3.5 h-3.5" }), x("agentsPage.retryValidation", "Retry validation")]
|
|
515
506
|
}),
|
|
516
|
-
|
|
507
|
+
ke && /* @__PURE__ */ m("div", {
|
|
517
508
|
className: "space-y-3 pt-2",
|
|
518
509
|
children: [
|
|
519
|
-
/* @__PURE__ */
|
|
510
|
+
/* @__PURE__ */ p("p", {
|
|
520
511
|
className: "text-sm font-medium text-text-primary",
|
|
521
|
-
children:
|
|
512
|
+
children: x("agentsPage.detectedAgentInfo", "Detected Agent Info")
|
|
522
513
|
}),
|
|
523
|
-
/* @__PURE__ */
|
|
514
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
524
515
|
className: "block text-xs font-medium text-text-secondary mb-1",
|
|
525
|
-
children:
|
|
526
|
-
}), /* @__PURE__ */
|
|
516
|
+
children: x("agentsPage.name", "Name")
|
|
517
|
+
}), /* @__PURE__ */ p("input", {
|
|
527
518
|
type: "text",
|
|
528
|
-
value:
|
|
529
|
-
onChange: (e) =>
|
|
530
|
-
placeholder:
|
|
519
|
+
value: E,
|
|
520
|
+
onChange: (e) => me(e.target.value),
|
|
521
|
+
placeholder: q,
|
|
531
522
|
className: "w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg"
|
|
532
523
|
})] }),
|
|
533
|
-
/* @__PURE__ */
|
|
524
|
+
/* @__PURE__ */ m("div", {
|
|
534
525
|
className: "grid grid-cols-2 gap-3",
|
|
535
|
-
children: [/* @__PURE__ */
|
|
526
|
+
children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
536
527
|
className: "block text-xs font-medium text-text-secondary mb-1",
|
|
537
|
-
children:
|
|
538
|
-
}), /* @__PURE__ */
|
|
539
|
-
value:
|
|
540
|
-
onChange: (e) =>
|
|
528
|
+
children: x("agentsPage.platform", "Platform")
|
|
529
|
+
}), /* @__PURE__ */ m("select", {
|
|
530
|
+
value: J,
|
|
531
|
+
onChange: (e) => ge(e.target.value),
|
|
541
532
|
className: "w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
|
|
542
533
|
children: [
|
|
543
|
-
/* @__PURE__ */
|
|
534
|
+
/* @__PURE__ */ p("option", {
|
|
544
535
|
value: "linux",
|
|
545
536
|
children: "Linux"
|
|
546
537
|
}),
|
|
547
|
-
/* @__PURE__ */
|
|
538
|
+
/* @__PURE__ */ p("option", {
|
|
548
539
|
value: "darwin",
|
|
549
540
|
children: "macOS"
|
|
550
541
|
}),
|
|
551
|
-
/* @__PURE__ */
|
|
542
|
+
/* @__PURE__ */ p("option", {
|
|
552
543
|
value: "windows",
|
|
553
544
|
children: "Windows"
|
|
554
545
|
})
|
|
555
546
|
]
|
|
556
|
-
})] }), /* @__PURE__ */
|
|
547
|
+
})] }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
557
548
|
className: "block text-xs font-medium text-text-secondary mb-1",
|
|
558
|
-
children:
|
|
559
|
-
}), /* @__PURE__ */
|
|
560
|
-
value:
|
|
561
|
-
onChange: (e) =>
|
|
549
|
+
children: x("agentsPage.architecture", "Architecture")
|
|
550
|
+
}), /* @__PURE__ */ m("select", {
|
|
551
|
+
value: _e,
|
|
552
|
+
onChange: (e) => ve(e.target.value),
|
|
562
553
|
className: "w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg",
|
|
563
554
|
children: [
|
|
564
|
-
/* @__PURE__ */
|
|
555
|
+
/* @__PURE__ */ p("option", {
|
|
565
556
|
value: "x86_64",
|
|
566
557
|
children: "x86_64"
|
|
567
558
|
}),
|
|
568
|
-
/* @__PURE__ */
|
|
559
|
+
/* @__PURE__ */ p("option", {
|
|
569
560
|
value: "arm64",
|
|
570
561
|
children: "arm64"
|
|
571
562
|
}),
|
|
572
|
-
/* @__PURE__ */
|
|
563
|
+
/* @__PURE__ */ p("option", {
|
|
573
564
|
value: "aarch64",
|
|
574
565
|
children: "aarch64"
|
|
575
566
|
})
|
|
@@ -578,44 +569,44 @@ function fe({ onSubmit: fe, onCancel: f, isLoading: p, onNavigate: m, targets: h
|
|
|
578
569
|
})
|
|
579
570
|
]
|
|
580
571
|
}),
|
|
581
|
-
|
|
572
|
+
xe && /* @__PURE__ */ m("div", {
|
|
582
573
|
className: "p-3 bg-status-error-bg/30 border border-status-error-text/20 rounded-lg",
|
|
583
|
-
children: [/* @__PURE__ */
|
|
574
|
+
children: [/* @__PURE__ */ m("div", {
|
|
584
575
|
className: "flex items-center gap-2",
|
|
585
|
-
children: [/* @__PURE__ */
|
|
576
|
+
children: [/* @__PURE__ */ p(d, { className: "w-5 h-5 text-status-error-text flex-shrink-0" }), /* @__PURE__ */ p("p", {
|
|
586
577
|
className: "text-sm text-status-error-text",
|
|
587
|
-
children:
|
|
578
|
+
children: xe
|
|
588
579
|
})]
|
|
589
|
-
}), /* @__PURE__ */
|
|
580
|
+
}), /* @__PURE__ */ m("div", {
|
|
590
581
|
className: "flex items-center gap-2 mt-3",
|
|
591
|
-
children: [/* @__PURE__ */
|
|
582
|
+
children: [/* @__PURE__ */ m("button", {
|
|
592
583
|
type: "button",
|
|
593
584
|
onClick: () => {
|
|
594
|
-
|
|
585
|
+
Y(null), C("details"), O(""), A(""), W(null), K(null);
|
|
595
586
|
},
|
|
596
587
|
className: "flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors",
|
|
597
|
-
children: [/* @__PURE__ */ u
|
|
598
|
-
}), /* @__PURE__ */
|
|
588
|
+
children: [/* @__PURE__ */ p(u, { className: "w-3.5 h-3.5" }), x("agentsPage.tryDifferentAgent", "Try Different Agent")]
|
|
589
|
+
}), /* @__PURE__ */ p("button", {
|
|
599
590
|
type: "button",
|
|
600
|
-
onClick:
|
|
591
|
+
onClick: g,
|
|
601
592
|
className: "px-3 py-1.5 text-sm font-medium text-text-secondary hover:text-text-primary transition-colors",
|
|
602
|
-
children:
|
|
593
|
+
children: x("agentsPage.close", "Close")
|
|
603
594
|
})]
|
|
604
595
|
})]
|
|
605
596
|
}),
|
|
606
|
-
/* @__PURE__ */
|
|
597
|
+
/* @__PURE__ */ m("div", {
|
|
607
598
|
className: "flex items-center justify-between pt-4",
|
|
608
|
-
children: [/* @__PURE__ */
|
|
599
|
+
children: [/* @__PURE__ */ m("button", {
|
|
609
600
|
type: "button",
|
|
610
|
-
onClick: () =>
|
|
601
|
+
onClick: () => C("details"),
|
|
611
602
|
className: "flex items-center gap-1 px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors",
|
|
612
|
-
children: [/* @__PURE__ */
|
|
613
|
-
}), /* @__PURE__ */
|
|
603
|
+
children: [/* @__PURE__ */ p(ee, { className: "w-4 h-4" }), x("agentsPage.back", "Back")]
|
|
604
|
+
}), /* @__PURE__ */ p("button", {
|
|
614
605
|
type: "button",
|
|
615
|
-
disabled: !
|
|
616
|
-
onClick:
|
|
606
|
+
disabled: !ke || _ || V,
|
|
607
|
+
onClick: Oe,
|
|
617
608
|
className: "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 disabled:opacity-50",
|
|
618
|
-
children:
|
|
609
|
+
children: _ ? /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(c, { className: "w-4 h-4 animate-spin" }), x("agentsPage.adding", "Adding...")] }) : /* @__PURE__ */ m(f, { children: [x("agentsPage.addAgent", "Add Agent"), /* @__PURE__ */ p(s, { className: "w-4 h-4" })] })
|
|
619
610
|
})]
|
|
620
611
|
})
|
|
621
612
|
]
|
|
@@ -626,6 +617,6 @@ function fe({ onSubmit: fe, onCancel: f, isLoading: p, onNavigate: m, targets: h
|
|
|
626
617
|
});
|
|
627
618
|
}
|
|
628
619
|
//#endregion
|
|
629
|
-
export {
|
|
620
|
+
export { h as AgentForm };
|
|
630
621
|
|
|
631
622
|
//# sourceMappingURL=AgentForm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentForm.js","names":[],"sources":["../../../src/components/agents/AgentForm.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n X,\n Eye,\n EyeOff,\n CheckCircle2,\n XCircle,\n Loader2,\n ChevronRight,\n ChevronLeft,\n ChevronDown,\n Copy,\n Check,\n Terminal,\n Download,\n RefreshCw,\n Plus,\n Settings2,\n} from 'lucide-react';\nimport { useProbeAgentTunnelLazyQuery } from '@/generated/wspace-operations';\nimport { SearchableSelect } from '@/components/shared';\nimport type { SearchableSelectOption } from '@/components/shared';\n\ntype WizardStage = 'details' | 'validate';\n\ninterface TargetOption {\n id: string;\n name: string;\n type: string;\n status: string;\n}\n\ninterface AgentFormProps {\n onSubmit: (data: Record<string, unknown>) => Promise<{ id: string } | void>;\n onCancel: () => void;\n isLoading?: boolean;\n /** Navigate to a path (used to go to agent details after creation) */\n onNavigate?: (path: string) => void;\n /** Available targets for the agent to be installed on */\n targets?: TargetOption[];\n /** Whether targets are still loading */\n targetsLoading?: boolean;\n /**\n * Create a new target inline. When provided, the form shows a\n * \"+ Create new target\" affordance that lets users create a DIRECT\n * target on the fly without leaving the dialog. Must return the new\n * target so the form can auto-select it.\n */\n onCreateTarget?: (name: string) => Promise<TargetOption | null>;\n}\n\nexport function AgentForm({\n onSubmit,\n onCancel,\n isLoading,\n onNavigate,\n targets,\n targetsLoading,\n onCreateTarget,\n}: AgentFormProps) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const [stage, setStage] = useState<WizardStage>('details');\n const [showApiKey, setShowApiKey] = useState(false);\n const [showInstallInstructions, setShowInstallInstructions] = useState(false);\n const [copiedCommand, setCopiedCommand] = useState<string | null>(null);\n\n // Stage 1: Basic details\n const [name, setName] = useState('');\n const [tunnelUrl, setTunnelUrl] = useState('');\n const [agentApiKey, setAgentApiKey] = useState('');\n const [selectedTargetId, setSelectedTargetId] = useState('');\n\n // Inline target creation state\n const [showInlineTarget, setShowInlineTarget] = useState(false);\n const [inlineTargetName, setInlineTargetName] = useState('');\n const [creatingTarget, setCreatingTarget] = useState(false);\n const [inlineTargetError, setInlineTargetError] = useState<string | null>(null);\n\n // Stage 2: Validation (via backend-proxied GraphQL query)\n const [validating, setValidating] = useState(false);\n const [healthResult, setHealthResult] = useState<{\n ok: boolean;\n data?: { status: string; version: string; uptime: number };\n error?: string;\n } | null>(null);\n const [identityResult, setIdentityResult] = useState<{\n ok: boolean;\n data?: { hostname: string; platform: string; arch: string };\n error?: string;\n } | null>(null);\n\n // Auto-detected fields (editable overrides)\n const [detectedHostname, setDetectedHostname] = useState('');\n const [detectedPlatform, setDetectedPlatform] = useState('linux');\n const [detectedArch, setDetectedArch] = useState('x86_64');\n const [detectedVersion, setDetectedVersion] = useState('1.0.0');\n\n // Error state for creation failures\n const [createError, setCreateError] = useState<string | null>(null);\n\n // Advanced options (Phase 5B: per-daemon profile name).\n // Defaults to \"default\" (autofilled but editable). Disclosure is closed\n // by default — users only need to touch this for multi-profile setups.\n const [showAdvanced, setShowAdvanced] = useState(false);\n const [profile, setProfile] = useState('default');\n\n // Backend-proxied GraphQL operations (server-side agent communication)\n const [probeAgentTunnel] = useProbeAgentTunnelLazyQuery();\n\n const copyToClipboard = useCallback((text: string, id: string) => {\n navigator.clipboard.writeText(text);\n setCopiedCommand(id);\n setTimeout(() => setCopiedCommand(null), 2000);\n }, []);\n\n const normalizeUrl = (url: string) => {\n let u = url.trim();\n if (u.endsWith('/')) u = u.slice(0, -1);\n return u;\n };\n\n // Validate the agent via the backend GraphQL proxy.\n // The backend calls /health and /api/agent/identity on the tunnel URL\n // server-side, avoiding direct browser-to-agent HTTP calls.\n const validateAgent = async () => {\n const baseUrl = normalizeUrl(tunnelUrl);\n if (!baseUrl) return;\n\n setValidating(true);\n setHealthResult(null);\n setIdentityResult(null);\n\n try {\n const { data, error } = await probeAgentTunnel({\n variables: {\n url: baseUrl,\n agentApiKey: agentApiKey || undefined,\n },\n });\n\n if (error) {\n setHealthResult({ ok: false, error: error.message });\n setIdentityResult({ ok: false, error: error.message });\n setValidating(false);\n return;\n }\n\n const probe = data?.probeAgentTunnel;\n if (!probe) {\n setHealthResult({ ok: false, error: 'No response from probe' });\n setIdentityResult({ ok: false, error: 'No response from probe' });\n setValidating(false);\n return;\n }\n\n // Map health result\n if (probe.healthOk) {\n setHealthResult({\n ok: true,\n data: {\n status: probe.healthStatus || 'healthy',\n version: probe.agentVersion || 'unknown',\n uptime: probe.uptime || 0,\n },\n });\n if (probe.agentVersion) setDetectedVersion(probe.agentVersion);\n } else {\n setHealthResult({\n ok: false,\n error: probe.healthError || 'Health check failed',\n });\n }\n\n // Map identity result\n if (probe.identityOk) {\n const hostname = probe.hostname || '';\n const platform = probe.platform || 'linux';\n const arch = probe.architecture || 'x86_64';\n setIdentityResult({\n ok: true,\n data: { hostname, platform, arch },\n });\n if (hostname) setDetectedHostname(hostname);\n if (platform) setDetectedPlatform(platform);\n if (arch) setDetectedArch(arch);\n if (!name && hostname) setName(hostname);\n } else {\n setIdentityResult({\n ok: false,\n error: probe.identityError || 'Identity check failed',\n });\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Probe request failed';\n setHealthResult({ ok: false, error: message });\n setIdentityResult({ ok: false, error: message });\n }\n\n setValidating(false);\n };\n\n // Create the agent and close the modal\n const handleCreateAgent = async () => {\n setCreateError(null);\n\n // Pipe the chosen profile through `metadata.profile`. Phase 5A (svc) is\n // adding first-class AgentProfile rows; in the meantime the backend\n // also reads `metadata.profile` so the create path keeps working\n // regardless of which side of the cut-over the cluster is on.\n const trimmedProfile = profile.trim() || 'default';\n const data: Record<string, unknown> = {\n name: name || detectedHostname || 'Unnamed Agent',\n hostname: detectedHostname || 'unknown',\n platform: detectedPlatform,\n architecture: detectedArch,\n version: detectedVersion,\n tunnelUrl: normalizeUrl(tunnelUrl),\n tunnelStatus: 'ACTIVE',\n agentApiKey,\n metadata: { profile: trimmedProfile },\n ...(selectedTargetId ? { targetId: selectedTargetId } : {}),\n };\n\n try {\n const result = await onSubmit(data);\n const newAgentId = result?.id || null;\n\n if (!newAgentId) {\n // Mutation succeeded but returned no agent ID — treat as failure\n setCreateError('Agent creation returned no ID. The agent may already exist.');\n return;\n }\n\n // Close the modal — the agent list will refetch automatically\n if (onNavigate) {\n onNavigate(`/agents/${newAgentId}`);\n } else {\n onCancel();\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to create agent';\n setCreateError(message);\n }\n };\n\n const isValidationPassed = healthResult?.ok && identityResult?.ok;\n const hasTargets = targets && targets.length > 0;\n // The user must either pick or inline-create a target if inline creation\n // is enabled; otherwise we only require it when targets already exist.\n const targetRequiredButMissing = onCreateTarget\n ? selectedTargetId.length === 0\n : hasTargets && selectedTargetId.length === 0;\n const canProceedToValidate = tunnelUrl.trim().length > 0 && !targetRequiredButMissing;\n\n const handleInlineCreateTarget = useCallback(async () => {\n if (!onCreateTarget || !inlineTargetName.trim()) return;\n setCreatingTarget(true);\n setInlineTargetError(null);\n try {\n const created = await onCreateTarget(inlineTargetName.trim());\n if (created) {\n setSelectedTargetId(created.id);\n setShowInlineTarget(false);\n setInlineTargetName('');\n } else {\n setInlineTargetError(\n tr('agentsPage.inlineTargetFailed', 'Failed to create target. Please try again.')\n );\n }\n } catch (err) {\n setInlineTargetError(err instanceof Error ? err.message : 'Failed to create target');\n } finally {\n setCreatingTarget(false);\n }\n }, [onCreateTarget, inlineTargetName, tr]);\n\n const CopyButton = ({ text, id }: { text: string; id: string }) => (\n <button\n type=\"button\"\n onClick={() => copyToClipboard(text, id)}\n className=\"p-1 rounded hover:bg-bg-elevated transition-colors\"\n title={tr('agentsPage.copy', 'Copy')}\n >\n {copiedCommand === id ? (\n <Check className=\"w-3.5 h-3.5 text-status-success-text\" />\n ) : (\n <Copy className=\"w-3.5 h-3.5 text-text-secondary\" />\n )}\n </button>\n );\n\n // Stepper\n const steps = [\n { key: 'details', label: 'Setup' },\n { key: 'validate', label: 'Validate' },\n ];\n\n const currentStepIndex = steps.findIndex((s) => s.key === stage);\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay\">\n <div className=\"w-full max-w-xl bg-bg-surface rounded-lg shadow-xl max-h-[90vh] overflow-y-auto\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default sticky top-0 bg-bg-surface z-10\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('agentsPage.addNewAgent', 'Add New Agent')}\n </h2>\n <button onClick={onCancel} className=\"p-1 rounded hover:bg-bg-sunken transition-colors\">\n <X className=\"w-5 h-5 text-text-secondary\" />\n </button>\n </div>\n\n {/* Stepper */}\n <div className=\"flex items-center gap-2 px-6 pt-4 pb-2\">\n {steps.map((step, i) => (\n <div key={step.key} className=\"flex items-center gap-2\">\n <div\n className={`flex items-center justify-center w-7 h-7 rounded-full text-xs font-semibold transition-colors ${\n i < currentStepIndex\n ? 'bg-status-success-bg text-status-success-text'\n : i === currentStepIndex\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {i < currentStepIndex ? <CheckCircle2 className=\"w-4 h-4\" /> : i + 1}\n </div>\n <span\n className={`text-sm ${i === currentStepIndex ? 'font-medium text-text-primary' : 'text-text-secondary'}`}\n >\n {step.label}\n </span>\n {i < steps.length - 1 && <ChevronRight className=\"w-4 h-4 text-text-muted\" />}\n </div>\n ))}\n </div>\n\n <div className=\"p-6\">\n {/* Stage 1: Setup */}\n {stage === 'details' && (\n <div className=\"space-y-4\">\n {/* Install instructions (collapsible) */}\n <div className=\"border border-border-default rounded-lg overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setShowInstallInstructions(!showInstallInstructions)}\n className=\"w-full flex items-center justify-between px-4 py-3 bg-bg-sunken hover:bg-bg-sunken/80 transition-colors\"\n >\n <div className=\"flex items-center gap-2\">\n <Download className=\"w-4 h-4 text-action-primary-bg\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.installInstructions', 'Agent Install Instructions')}\n </span>\n </div>\n <ChevronRight\n className={`w-4 h-4 text-text-secondary transition-transform ${showInstallInstructions ? 'rotate-90' : ''}`}\n />\n </button>\n {showInstallInstructions && (\n <div className=\"px-4 py-3 space-y-3 border-t border-border-default\">\n <div className=\"space-y-2\">\n {[\n {\n label: tr('agentsPage.installStep1', '1. Install the agent CLI'),\n cmd: 'npm install -g @vibecontrols/agent@latest',\n },\n {\n label: tr('agentsPage.installStep2', '2. Start the agent'),\n cmd: 'vibe start',\n },\n {\n label: tr('agentsPage.installStep3', '3. Get the API key'),\n cmd: 'vibe key',\n },\n {\n label: tr('agentsPage.installStep4', '4. Start the tunnel'),\n cmd: 'vibe tunnel agent --start',\n },\n ].map((step) => (\n <div key={step.cmd}>\n <p className=\"text-xs text-text-secondary mb-1\">{step.label}</p>\n <div className=\"flex items-center gap-2 bg-bg-sunken rounded-md px-3 py-1.5 font-mono text-xs text-text-primary\">\n <Terminal className=\"w-3 h-3 text-text-muted flex-shrink-0\" />\n <code className=\"flex-1\">{step.cmd}</code>\n <CopyButton text={step.cmd} id={step.cmd} />\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Target Selection — with inline creation */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.target', 'Target')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n\n {hasTargets && !showInlineTarget && (\n <>\n <SearchableSelect\n placeholder={tr('agentsPage.selectTarget', 'Select a target...')}\n searchPlaceholder={tr('agentsPage.searchTargets', 'Search targets...')}\n options={(targets ?? []).map(\n (tgt): SearchableSelectOption => ({\n value: tgt.id,\n label: tgt.name,\n description: `${tgt.type}${tgt.status ? ` · ${tgt.status}` : ''}`,\n })\n )}\n value={selectedTargetId}\n onChange={setSelectedTargetId}\n clearable\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'agentsPage.targetDescription',\n 'The target machine this agent will be installed on.'\n )}{' '}\n {onCreateTarget && (\n <button\n type=\"button\"\n onClick={() => {\n setShowInlineTarget(true);\n setInlineTargetName(name.trim() || '');\n }}\n className=\"text-action-primary-bg hover:underline inline-flex items-center gap-1\"\n >\n <Plus className=\"w-3 h-3\" />\n {tr('agentsPage.createNewTarget', 'Create a new target')}\n </button>\n )}\n </p>\n </>\n )}\n\n {/* Empty state prompt (no targets exist yet) */}\n {!hasTargets && !targetsLoading && onCreateTarget && !showInlineTarget && (\n <div className=\"p-3 bg-bg-sunken border border-border-default rounded-lg\">\n <p className=\"text-sm text-text-secondary mb-2\">\n {tr(\n 'agentsPage.noTargetsInlinePrompt',\n \"You don't have any targets yet. Create one now to install this agent on it.\"\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => {\n setShowInlineTarget(true);\n setInlineTargetName(name.trim() || '');\n }}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:opacity-90\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('agentsPage.createFirstTarget', 'Create first target')}\n </button>\n </div>\n )}\n\n {/* Inline creation form */}\n {showInlineTarget && onCreateTarget && (\n <div className=\"p-3 bg-bg-sunken border border-border-default rounded-lg space-y-2\">\n <p className=\"text-xs font-medium text-text-secondary\">\n {tr(\n 'agentsPage.newDirectTarget',\n 'New target (Direct — you can change the type later)'\n )}\n </p>\n <input\n type=\"text\"\n value={inlineTargetName}\n onChange={(e) => setInlineTargetName(e.target.value)}\n placeholder={tr('agentsPage.targetName', 'Target name')}\n className=\"w-full px-3 py-2 text-sm bg-bg-elevated border border-border-default rounded-md text-text-primary placeholder-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n void handleInlineCreateTarget();\n }\n }}\n />\n {inlineTargetError && (\n <p className=\"text-xs text-status-error-text\">{inlineTargetError}</p>\n )}\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => void handleInlineCreateTarget()}\n disabled={!inlineTargetName.trim() || creatingTarget}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:opacity-90 disabled:opacity-50\"\n >\n {creatingTarget ? (\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\n ) : (\n <Check className=\"w-3.5 h-3.5\" />\n )}\n {tr('agentsPage.create', 'Create')}\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setShowInlineTarget(false);\n setInlineTargetName('');\n setInlineTargetError(null);\n }}\n className=\"px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr('agentsPage.cancel', 'Cancel')}\n </button>\n </div>\n </div>\n )}\n\n {/* Loading placeholder */}\n {targetsLoading && !hasTargets && (\n <div className=\"p-3 bg-bg-sunken border border-border-default rounded-lg flex items-center gap-2 text-sm text-text-secondary\">\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n {tr('agentsPage.loadingTargets', 'Loading targets...')}\n </div>\n )}\n </div>\n\n {/* API/Tunnel URL */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.apiTunnelUrl', 'API / Tunnel URL')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"url\"\n value={tunnelUrl}\n onChange={(e) => setTunnelUrl(e.target.value)}\n placeholder=\"https://your-tunnel.trycloudflare.com\"\n required\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'agentsPage.tunnelUrlHint',\n \"The agent's tunnel URL or local API URL (e.g. http://localhost:3005)\"\n )}\n </p>\n </div>\n\n {/* Agent API Key */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.agentApiKey', 'Agent API Key')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"relative\">\n <input\n type={showApiKey ? 'text' : 'password'}\n value={agentApiKey}\n onChange={(e) => setAgentApiKey(e.target.value)}\n placeholder=\"vcak_...\"\n required\n className=\"w-full px-3 py-2 pr-10 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n <button\n type=\"button\"\n onClick={() => setShowApiKey(!showApiKey)}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 p-1 rounded hover:bg-bg-elevated transition-colors\"\n >\n {showApiKey ? (\n <EyeOff className=\"w-4 h-4 text-text-secondary\" />\n ) : (\n <Eye className=\"w-4 h-4 text-text-secondary\" />\n )}\n </button>\n </div>\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr('agentsPage.apiKeyHint', 'Run')}{' '}\n <code className=\"bg-bg-sunken px-1 rounded\">vibe key</code>{' '}\n {tr(\n 'agentsPage.apiKeyHintSuffix',\n 'on the agent to get this. Changes on restart.'\n )}\n </p>\n </div>\n\n {/* Advanced options — per-daemon profile name (Phase 5B) */}\n <div className=\"border border-border-default rounded-lg overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setShowAdvanced((v) => !v)}\n className=\"w-full flex items-center justify-between px-4 py-2.5 bg-bg-sunken hover:bg-bg-sunken/80 transition-colors\"\n aria-expanded={showAdvanced}\n data-testid=\"agent-form-advanced-toggle\"\n >\n <div className=\"flex items-center gap-2\">\n <Settings2 className=\"w-4 h-4 text-text-secondary\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.advancedOptions', 'Advanced options')}\n </span>\n </div>\n <ChevronDown\n className={`w-4 h-4 text-text-secondary transition-transform ${showAdvanced ? 'rotate-180' : ''}`}\n />\n </button>\n {showAdvanced && (\n <div className=\"px-4 py-3 space-y-3 border-t border-border-default\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.profileName', 'Profile name')}\n </label>\n <input\n type=\"text\"\n value={profile}\n onChange={(e) => setProfile(e.target.value)}\n placeholder=\"default\"\n className=\"w-full px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n data-testid=\"agent-form-profile-input\"\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'agentsPage.profileNameHint',\n 'Each profile runs an isolated CLI on the daemon. Leave as \"default\" unless you want this agent to host multiple parallel profiles.'\n )}\n </p>\n </div>\n </div>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center justify-between pt-4\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n {tr('agentsPage.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n disabled={!canProceedToValidate}\n onClick={() => {\n setStage('validate');\n validateAgent();\n }}\n className=\"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 disabled:opacity-50\"\n >\n {tr('agentsPage.nextValidate', 'Next: Validate')}\n <ChevronRight className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n )}\n\n {/* Stage 2: Validate */}\n {stage === 'validate' && (\n <div className=\"space-y-4\">\n {/* Validation Results */}\n <div className=\"space-y-3\">\n {/* Health Check */}\n <div\n className={`flex items-center gap-3 p-3 rounded-lg border ${\n healthResult === null\n ? 'border-border-default bg-bg-sunken'\n : healthResult.ok\n ? 'border-status-success-text/20 bg-status-success-bg/30'\n : 'border-status-error-text/20 bg-status-error-bg/30'\n }`}\n >\n {validating && !healthResult ? (\n <Loader2 className=\"w-5 h-5 text-text-secondary animate-spin\" />\n ) : healthResult?.ok ? (\n <CheckCircle2 className=\"w-5 h-5 text-status-success-text\" />\n ) : healthResult ? (\n <XCircle className=\"w-5 h-5 text-status-error-text\" />\n ) : (\n <div className=\"w-5 h-5 rounded-full border-2 border-border-default\" />\n )}\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.healthCheck', 'Health Check')}\n </p>\n {healthResult?.ok && healthResult.data && (\n <p className=\"text-xs text-text-secondary\">\n Status: {healthResult.data.status} | Version: {healthResult.data.version} |\n Uptime: {Math.round(healthResult.data.uptime)}s\n </p>\n )}\n {healthResult && !healthResult.ok && (\n <p className=\"text-xs text-status-error-text\">{healthResult.error}</p>\n )}\n </div>\n </div>\n\n {/* API Access Check */}\n <div\n className={`flex items-center gap-3 p-3 rounded-lg border ${\n identityResult === null\n ? 'border-border-default bg-bg-sunken'\n : identityResult.ok\n ? 'border-status-success-text/20 bg-status-success-bg/30'\n : 'border-status-error-text/20 bg-status-error-bg/30'\n }`}\n >\n {validating && !identityResult ? (\n <Loader2 className=\"w-5 h-5 text-text-secondary animate-spin\" />\n ) : identityResult?.ok ? (\n <CheckCircle2 className=\"w-5 h-5 text-status-success-text\" />\n ) : identityResult ? (\n <XCircle className=\"w-5 h-5 text-status-error-text\" />\n ) : (\n <div className=\"w-5 h-5 rounded-full border-2 border-border-default\" />\n )}\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.apiAccess', 'API Access')}\n </p>\n {identityResult?.ok && identityResult.data && (\n <p className=\"text-xs text-text-secondary\">\n Host: {identityResult.data.hostname} | {identityResult.data.platform} /{' '}\n {identityResult.data.arch}\n </p>\n )}\n {identityResult && !identityResult.ok && (\n <p className=\"text-xs text-status-error-text\">{identityResult.error}</p>\n )}\n </div>\n </div>\n </div>\n\n {/* Retry button */}\n {!validating && (!healthResult?.ok || !identityResult?.ok) && (\n <button\n type=\"button\"\n onClick={validateAgent}\n className=\"flex items-center gap-2 px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n <RefreshCw className=\"w-3.5 h-3.5\" />\n {tr('agentsPage.retryValidation', 'Retry validation')}\n </button>\n )}\n\n {/* Detected info (editable overrides) */}\n {isValidationPassed && (\n <div className=\"space-y-3 pt-2\">\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.detectedAgentInfo', 'Detected Agent Info')}\n </p>\n\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('agentsPage.name', 'Name')}\n </label>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={detectedHostname}\n className=\"w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('agentsPage.platform', 'Platform')}\n </label>\n <select\n value={detectedPlatform}\n onChange={(e) => setDetectedPlatform(e.target.value)}\n className=\"w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value=\"linux\">Linux</option>\n <option value=\"darwin\">macOS</option>\n <option value=\"windows\">Windows</option>\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('agentsPage.architecture', 'Architecture')}\n </label>\n <select\n value={detectedArch}\n onChange={(e) => setDetectedArch(e.target.value)}\n className=\"w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value=\"x86_64\">x86_64</option>\n <option value=\"arm64\">arm64</option>\n <option value=\"aarch64\">aarch64</option>\n </select>\n </div>\n </div>\n </div>\n )}\n\n {/* Creation error */}\n {createError && (\n <div className=\"p-3 bg-status-error-bg/30 border border-status-error-text/20 rounded-lg\">\n <div className=\"flex items-center gap-2\">\n <XCircle className=\"w-5 h-5 text-status-error-text flex-shrink-0\" />\n <p className=\"text-sm text-status-error-text\">{createError}</p>\n </div>\n <div className=\"flex items-center gap-2 mt-3\">\n <button\n type=\"button\"\n onClick={() => {\n setCreateError(null);\n // Reset form to allow entering different credentials\n setStage('details');\n setTunnelUrl('');\n setAgentApiKey('');\n setHealthResult(null);\n setIdentityResult(null);\n }}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n <RefreshCw className=\"w-3.5 h-3.5\" />\n {tr('agentsPage.tryDifferentAgent', 'Try Different Agent')}\n </button>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-3 py-1.5 text-sm font-medium text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr('agentsPage.close', 'Close')}\n </button>\n </div>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex items-center justify-between pt-4\">\n <button\n type=\"button\"\n onClick={() => setStage('details')}\n className=\"flex items-center gap-1 px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n <ChevronLeft className=\"w-4 h-4\" />\n {tr('agentsPage.back', 'Back')}\n </button>\n <button\n type=\"button\"\n disabled={!isValidationPassed || isLoading || validating}\n onClick={handleCreateAgent}\n className=\"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 disabled:opacity-50\"\n >\n {isLoading ? (\n <>\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n {tr('agentsPage.adding', 'Adding...')}\n </>\n ) : (\n <>\n {tr('agentsPage.addAgent', 'Add Agent')}\n <ChevronRight className=\"w-4 h-4\" />\n </>\n )}\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AgentForm.js","names":[],"sources":["../../../src/components/agents/AgentForm.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n X,\n Eye,\n EyeOff,\n CheckCircle2,\n XCircle,\n Loader2,\n ChevronRight,\n ChevronLeft,\n ChevronDown,\n Copy,\n Check,\n Terminal,\n Download,\n RefreshCw,\n Plus,\n Settings2,\n} from 'lucide-react';\n// useProbeAgentTunnelLazyQuery removed: validate now hits the agent's tunnel\n// URL directly from the browser (see validateAgent below).\nimport { SearchableSelect } from '@/components/shared';\nimport type { SearchableSelectOption } from '@/components/shared';\n\ntype WizardStage = 'details' | 'validate';\n\ninterface TargetOption {\n id: string;\n name: string;\n type: string;\n status: string;\n}\n\ninterface AgentFormProps {\n onSubmit: (data: Record<string, unknown>) => Promise<{ id: string } | void>;\n onCancel: () => void;\n isLoading?: boolean;\n /** Navigate to a path (used to go to agent details after creation) */\n onNavigate?: (path: string) => void;\n /** Available targets for the agent to be installed on */\n targets?: TargetOption[];\n /** Whether targets are still loading */\n targetsLoading?: boolean;\n /**\n * Create a new target inline. When provided, the form shows a\n * \"+ Create new target\" affordance that lets users create a DIRECT\n * target on the fly without leaving the dialog. Must return the new\n * target so the form can auto-select it.\n */\n onCreateTarget?: (name: string) => Promise<TargetOption | null>;\n}\n\nexport function AgentForm({\n onSubmit,\n onCancel,\n isLoading,\n onNavigate,\n targets,\n targetsLoading,\n onCreateTarget,\n}: AgentFormProps) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const [stage, setStage] = useState<WizardStage>('details');\n const [showApiKey, setShowApiKey] = useState(false);\n const [showInstallInstructions, setShowInstallInstructions] = useState(false);\n const [copiedCommand, setCopiedCommand] = useState<string | null>(null);\n\n // Stage 1: Basic details\n const [name, setName] = useState('');\n const [tunnelUrl, setTunnelUrl] = useState('');\n const [agentApiKey, setAgentApiKey] = useState('');\n const [selectedTargetId, setSelectedTargetId] = useState('');\n\n // Inline target creation state\n const [showInlineTarget, setShowInlineTarget] = useState(false);\n const [inlineTargetName, setInlineTargetName] = useState('');\n const [creatingTarget, setCreatingTarget] = useState(false);\n const [inlineTargetError, setInlineTargetError] = useState<string | null>(null);\n\n // Stage 2: Validation (via backend-proxied GraphQL query)\n const [validating, setValidating] = useState(false);\n const [healthResult, setHealthResult] = useState<{\n ok: boolean;\n data?: { status: string; version: string; uptime: number };\n error?: string;\n } | null>(null);\n const [identityResult, setIdentityResult] = useState<{\n ok: boolean;\n data?: { hostname: string; platform: string; arch: string };\n error?: string;\n } | null>(null);\n\n // Auto-detected fields (editable overrides)\n const [detectedHostname, setDetectedHostname] = useState('');\n const [detectedPlatform, setDetectedPlatform] = useState('linux');\n const [detectedArch, setDetectedArch] = useState('x86_64');\n const [detectedVersion, setDetectedVersion] = useState('1.0.0');\n\n // Error state for creation failures\n const [createError, setCreateError] = useState<string | null>(null);\n\n // Advanced options (Phase 5B: per-daemon profile name).\n // Defaults to \"default\" (autofilled but editable). Disclosure is closed\n // by default — users only need to touch this for multi-profile setups.\n const [showAdvanced, setShowAdvanced] = useState(false);\n const [profile, setProfile] = useState('default');\n\n const copyToClipboard = useCallback((text: string, id: string) => {\n navigator.clipboard.writeText(text);\n setCopiedCommand(id);\n setTimeout(() => setCopiedCommand(null), 2000);\n }, []);\n\n const normalizeUrl = (url: string) => {\n let u = url.trim();\n if (u.endsWith('/')) u = u.slice(0, -1);\n return u;\n };\n\n // Validate the agent by probing /health and /api/profiles/default/agent/identity\n // directly from the browser. The agent exposes CORS-allowed endpoints for\n // app.vibecontrols.com (see agent's createApp() — `@elysiajs/cors` is wired\n // for the host origin), so the browser can reach the tunnel URL without a\n // backend proxy. The earlier backend-proxy approach (probeAgentTunnel query)\n // is still wired into the schema, but in production we observed the proxy\n // hanging at the ACA egress layer regardless of timeout, so we bypass it for\n // the wizard validate step. Each fetch is bounded by a 10s AbortSignal so a\n // dead tunnel surfaces a real error instead of an infinite spinner.\n const validateAgent = async () => {\n const baseUrl = normalizeUrl(tunnelUrl);\n if (!baseUrl) return;\n\n setValidating(true);\n setHealthResult(null);\n setIdentityResult(null);\n\n const probeHealth = async (): Promise<void> => {\n try {\n const res = await fetch(`${baseUrl}/health`, {\n signal: AbortSignal.timeout(10_000),\n });\n if (!res.ok) {\n setHealthResult({ ok: false, error: `HTTP ${String(res.status)}: ${res.statusText}` });\n return;\n }\n const data = (await res.json()) as {\n status?: string;\n version?: string;\n uptime?: number;\n };\n setHealthResult({\n ok: true,\n data: {\n status: data.status || 'healthy',\n version: data.version || 'unknown',\n uptime: data.uptime || 0,\n },\n });\n if (data.version) setDetectedVersion(data.version);\n } catch (err) {\n const isTimeout = err instanceof DOMException && err.name === 'AbortError';\n setHealthResult({\n ok: false,\n error: isTimeout ? 'Health check timed out after 10s' :\n (err instanceof Error ? err.message : 'Health check failed'),\n });\n }\n };\n\n const probeIdentity = async (): Promise<void> => {\n try {\n const headers: Record<string, string> = {};\n if (agentApiKey) headers['x-agent-api-key'] = agentApiKey;\n const res = await fetch(`${baseUrl}/api/profiles/default/agent/identity`, {\n headers,\n signal: AbortSignal.timeout(10_000),\n });\n if (!res.ok) {\n setIdentityResult({\n ok: false,\n error: res.status === 401 ? 'Invalid API key' : `HTTP ${String(res.status)}: ${res.statusText}`,\n });\n return;\n }\n const data = (await res.json()) as {\n hostname?: string;\n platform?: string;\n arch?: string;\n };\n const hostname = data.hostname || '';\n const platform = data.platform || 'linux';\n const arch = data.arch || 'x86_64';\n setIdentityResult({ ok: true, data: { hostname, platform, arch } });\n if (hostname) setDetectedHostname(hostname);\n if (platform) setDetectedPlatform(platform);\n if (arch) setDetectedArch(arch);\n if (!name && hostname) setName(hostname);\n } catch (err) {\n const isTimeout = err instanceof DOMException && err.name === 'AbortError';\n setIdentityResult({\n ok: false,\n error: isTimeout ? 'Identity check timed out after 10s' :\n (err instanceof Error ? err.message : 'Identity check failed'),\n });\n }\n };\n\n // Run both probes in parallel so the user sees results as fast as the\n // slower of the two — instead of stacking 20s in series on failure paths.\n await Promise.all([probeHealth(), probeIdentity()]);\n\n setValidating(false);\n };\n\n // Create the agent and close the modal\n const handleCreateAgent = async () => {\n setCreateError(null);\n\n // Pipe the chosen profile through `metadata.profile`. Phase 5A (svc) is\n // adding first-class AgentProfile rows; in the meantime the backend\n // also reads `metadata.profile` so the create path keeps working\n // regardless of which side of the cut-over the cluster is on.\n const trimmedProfile = profile.trim() || 'default';\n const data: Record<string, unknown> = {\n name: name || detectedHostname || 'Unnamed Agent',\n hostname: detectedHostname || 'unknown',\n platform: detectedPlatform,\n architecture: detectedArch,\n version: detectedVersion,\n tunnelUrl: normalizeUrl(tunnelUrl),\n tunnelStatus: 'ACTIVE',\n agentApiKey,\n metadata: { profile: trimmedProfile },\n ...(selectedTargetId ? { targetId: selectedTargetId } : {}),\n };\n\n try {\n const result = await onSubmit(data);\n const newAgentId = result?.id || null;\n\n if (!newAgentId) {\n // Mutation succeeded but returned no agent ID — treat as failure\n setCreateError('Agent creation returned no ID. The agent may already exist.');\n return;\n }\n\n // Close the modal — the agent list will refetch automatically\n if (onNavigate) {\n onNavigate(`/agents/${newAgentId}`);\n } else {\n onCancel();\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to create agent';\n setCreateError(message);\n }\n };\n\n const isValidationPassed = healthResult?.ok && identityResult?.ok;\n const hasTargets = targets && targets.length > 0;\n // The user must either pick or inline-create a target if inline creation\n // is enabled; otherwise we only require it when targets already exist.\n const targetRequiredButMissing = onCreateTarget\n ? selectedTargetId.length === 0\n : hasTargets && selectedTargetId.length === 0;\n const canProceedToValidate = tunnelUrl.trim().length > 0 && !targetRequiredButMissing;\n\n const handleInlineCreateTarget = useCallback(async () => {\n if (!onCreateTarget || !inlineTargetName.trim()) return;\n setCreatingTarget(true);\n setInlineTargetError(null);\n try {\n const created = await onCreateTarget(inlineTargetName.trim());\n if (created) {\n setSelectedTargetId(created.id);\n setShowInlineTarget(false);\n setInlineTargetName('');\n } else {\n setInlineTargetError(\n tr('agentsPage.inlineTargetFailed', 'Failed to create target. Please try again.')\n );\n }\n } catch (err) {\n setInlineTargetError(err instanceof Error ? err.message : 'Failed to create target');\n } finally {\n setCreatingTarget(false);\n }\n }, [onCreateTarget, inlineTargetName, tr]);\n\n const CopyButton = ({ text, id }: { text: string; id: string }) => (\n <button\n type=\"button\"\n onClick={() => copyToClipboard(text, id)}\n className=\"p-1 rounded hover:bg-bg-elevated transition-colors\"\n title={tr('agentsPage.copy', 'Copy')}\n >\n {copiedCommand === id ? (\n <Check className=\"w-3.5 h-3.5 text-status-success-text\" />\n ) : (\n <Copy className=\"w-3.5 h-3.5 text-text-secondary\" />\n )}\n </button>\n );\n\n // Stepper\n const steps = [\n { key: 'details', label: 'Setup' },\n { key: 'validate', label: 'Validate' },\n ];\n\n const currentStepIndex = steps.findIndex((s) => s.key === stage);\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay\">\n <div className=\"w-full max-w-xl bg-bg-surface rounded-lg shadow-xl max-h-[90vh] overflow-y-auto\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default sticky top-0 bg-bg-surface z-10\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('agentsPage.addNewAgent', 'Add New Agent')}\n </h2>\n <button onClick={onCancel} className=\"p-1 rounded hover:bg-bg-sunken transition-colors\">\n <X className=\"w-5 h-5 text-text-secondary\" />\n </button>\n </div>\n\n {/* Stepper */}\n <div className=\"flex items-center gap-2 px-6 pt-4 pb-2\">\n {steps.map((step, i) => (\n <div key={step.key} className=\"flex items-center gap-2\">\n <div\n className={`flex items-center justify-center w-7 h-7 rounded-full text-xs font-semibold transition-colors ${\n i < currentStepIndex\n ? 'bg-status-success-bg text-status-success-text'\n : i === currentStepIndex\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {i < currentStepIndex ? <CheckCircle2 className=\"w-4 h-4\" /> : i + 1}\n </div>\n <span\n className={`text-sm ${i === currentStepIndex ? 'font-medium text-text-primary' : 'text-text-secondary'}`}\n >\n {step.label}\n </span>\n {i < steps.length - 1 && <ChevronRight className=\"w-4 h-4 text-text-muted\" />}\n </div>\n ))}\n </div>\n\n <div className=\"p-6\">\n {/* Stage 1: Setup */}\n {stage === 'details' && (\n <div className=\"space-y-4\">\n {/* Install instructions (collapsible) */}\n <div className=\"border border-border-default rounded-lg overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setShowInstallInstructions(!showInstallInstructions)}\n className=\"w-full flex items-center justify-between px-4 py-3 bg-bg-sunken hover:bg-bg-sunken/80 transition-colors\"\n >\n <div className=\"flex items-center gap-2\">\n <Download className=\"w-4 h-4 text-action-primary-bg\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.installInstructions', 'Agent Install Instructions')}\n </span>\n </div>\n <ChevronRight\n className={`w-4 h-4 text-text-secondary transition-transform ${showInstallInstructions ? 'rotate-90' : ''}`}\n />\n </button>\n {showInstallInstructions && (\n <div className=\"px-4 py-3 space-y-3 border-t border-border-default\">\n <div className=\"space-y-2\">\n {[\n {\n label: tr('agentsPage.installStep1', '1. Install the agent CLI'),\n cmd: 'npm install -g @vibecontrols/agent@latest',\n },\n {\n label: tr('agentsPage.installStep2', '2. Start the agent'),\n cmd: 'vibe start',\n },\n {\n label: tr('agentsPage.installStep3', '3. Get the API key'),\n cmd: 'vibe key',\n },\n {\n label: tr('agentsPage.installStep4', '4. Start the tunnel'),\n cmd: 'vibe tunnel agent --start',\n },\n ].map((step) => (\n <div key={step.cmd}>\n <p className=\"text-xs text-text-secondary mb-1\">{step.label}</p>\n <div className=\"flex items-center gap-2 bg-bg-sunken rounded-md px-3 py-1.5 font-mono text-xs text-text-primary\">\n <Terminal className=\"w-3 h-3 text-text-muted flex-shrink-0\" />\n <code className=\"flex-1\">{step.cmd}</code>\n <CopyButton text={step.cmd} id={step.cmd} />\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Target Selection — with inline creation */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.target', 'Target')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n\n {hasTargets && !showInlineTarget && (\n <>\n <SearchableSelect\n placeholder={tr('agentsPage.selectTarget', 'Select a target...')}\n searchPlaceholder={tr('agentsPage.searchTargets', 'Search targets...')}\n options={(targets ?? []).map(\n (tgt): SearchableSelectOption => ({\n value: tgt.id,\n label: tgt.name,\n description: `${tgt.type}${tgt.status ? ` · ${tgt.status}` : ''}`,\n })\n )}\n value={selectedTargetId}\n onChange={setSelectedTargetId}\n clearable\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'agentsPage.targetDescription',\n 'The target machine this agent will be installed on.'\n )}{' '}\n {onCreateTarget && (\n <button\n type=\"button\"\n onClick={() => {\n setShowInlineTarget(true);\n setInlineTargetName(name.trim() || '');\n }}\n className=\"text-action-primary-bg hover:underline inline-flex items-center gap-1\"\n >\n <Plus className=\"w-3 h-3\" />\n {tr('agentsPage.createNewTarget', 'Create a new target')}\n </button>\n )}\n </p>\n </>\n )}\n\n {/* Empty state prompt (no targets exist yet) */}\n {!hasTargets && !targetsLoading && onCreateTarget && !showInlineTarget && (\n <div className=\"p-3 bg-bg-sunken border border-border-default rounded-lg\">\n <p className=\"text-sm text-text-secondary mb-2\">\n {tr(\n 'agentsPage.noTargetsInlinePrompt',\n \"You don't have any targets yet. Create one now to install this agent on it.\"\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => {\n setShowInlineTarget(true);\n setInlineTargetName(name.trim() || '');\n }}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:opacity-90\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('agentsPage.createFirstTarget', 'Create first target')}\n </button>\n </div>\n )}\n\n {/* Inline creation form */}\n {showInlineTarget && onCreateTarget && (\n <div className=\"p-3 bg-bg-sunken border border-border-default rounded-lg space-y-2\">\n <p className=\"text-xs font-medium text-text-secondary\">\n {tr(\n 'agentsPage.newDirectTarget',\n 'New target (Direct — you can change the type later)'\n )}\n </p>\n <input\n type=\"text\"\n value={inlineTargetName}\n onChange={(e) => setInlineTargetName(e.target.value)}\n placeholder={tr('agentsPage.targetName', 'Target name')}\n className=\"w-full px-3 py-2 text-sm bg-bg-elevated border border-border-default rounded-md text-text-primary placeholder-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n void handleInlineCreateTarget();\n }\n }}\n />\n {inlineTargetError && (\n <p className=\"text-xs text-status-error-text\">{inlineTargetError}</p>\n )}\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => void handleInlineCreateTarget()}\n disabled={!inlineTargetName.trim() || creatingTarget}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:opacity-90 disabled:opacity-50\"\n >\n {creatingTarget ? (\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\n ) : (\n <Check className=\"w-3.5 h-3.5\" />\n )}\n {tr('agentsPage.create', 'Create')}\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setShowInlineTarget(false);\n setInlineTargetName('');\n setInlineTargetError(null);\n }}\n className=\"px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr('agentsPage.cancel', 'Cancel')}\n </button>\n </div>\n </div>\n )}\n\n {/* Loading placeholder */}\n {targetsLoading && !hasTargets && (\n <div className=\"p-3 bg-bg-sunken border border-border-default rounded-lg flex items-center gap-2 text-sm text-text-secondary\">\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n {tr('agentsPage.loadingTargets', 'Loading targets...')}\n </div>\n )}\n </div>\n\n {/* API/Tunnel URL */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.apiTunnelUrl', 'API / Tunnel URL')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"url\"\n value={tunnelUrl}\n onChange={(e) => setTunnelUrl(e.target.value)}\n placeholder=\"https://your-tunnel.trycloudflare.com\"\n required\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'agentsPage.tunnelUrlHint',\n \"The agent's tunnel URL or local API URL (e.g. http://localhost:3005)\"\n )}\n </p>\n </div>\n\n {/* Agent API Key */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.agentApiKey', 'Agent API Key')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <div className=\"relative\">\n <input\n type={showApiKey ? 'text' : 'password'}\n value={agentApiKey}\n onChange={(e) => setAgentApiKey(e.target.value)}\n placeholder=\"vcak_...\"\n required\n className=\"w-full px-3 py-2 pr-10 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n <button\n type=\"button\"\n onClick={() => setShowApiKey(!showApiKey)}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 p-1 rounded hover:bg-bg-elevated transition-colors\"\n >\n {showApiKey ? (\n <EyeOff className=\"w-4 h-4 text-text-secondary\" />\n ) : (\n <Eye className=\"w-4 h-4 text-text-secondary\" />\n )}\n </button>\n </div>\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr('agentsPage.apiKeyHint', 'Run')}{' '}\n <code className=\"bg-bg-sunken px-1 rounded\">vibe key</code>{' '}\n {tr(\n 'agentsPage.apiKeyHintSuffix',\n 'on the agent to get this. Changes on restart.'\n )}\n </p>\n </div>\n\n {/* Advanced options — per-daemon profile name (Phase 5B) */}\n <div className=\"border border-border-default rounded-lg overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setShowAdvanced((v) => !v)}\n className=\"w-full flex items-center justify-between px-4 py-2.5 bg-bg-sunken hover:bg-bg-sunken/80 transition-colors\"\n aria-expanded={showAdvanced}\n data-testid=\"agent-form-advanced-toggle\"\n >\n <div className=\"flex items-center gap-2\">\n <Settings2 className=\"w-4 h-4 text-text-secondary\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.advancedOptions', 'Advanced options')}\n </span>\n </div>\n <ChevronDown\n className={`w-4 h-4 text-text-secondary transition-transform ${showAdvanced ? 'rotate-180' : ''}`}\n />\n </button>\n {showAdvanced && (\n <div className=\"px-4 py-3 space-y-3 border-t border-border-default\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('agentsPage.profileName', 'Profile name')}\n </label>\n <input\n type=\"text\"\n value={profile}\n onChange={(e) => setProfile(e.target.value)}\n placeholder=\"default\"\n className=\"w-full px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n data-testid=\"agent-form-profile-input\"\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'agentsPage.profileNameHint',\n 'Each profile runs an isolated CLI on the daemon. Leave as \"default\" unless you want this agent to host multiple parallel profiles.'\n )}\n </p>\n </div>\n </div>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center justify-between pt-4\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n {tr('agentsPage.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n disabled={!canProceedToValidate}\n onClick={() => {\n setStage('validate');\n validateAgent();\n }}\n className=\"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 disabled:opacity-50\"\n >\n {tr('agentsPage.nextValidate', 'Next: Validate')}\n <ChevronRight className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n )}\n\n {/* Stage 2: Validate */}\n {stage === 'validate' && (\n <div className=\"space-y-4\">\n {/* Validation Results */}\n <div className=\"space-y-3\">\n {/* Health Check */}\n <div\n className={`flex items-center gap-3 p-3 rounded-lg border ${\n healthResult === null\n ? 'border-border-default bg-bg-sunken'\n : healthResult.ok\n ? 'border-status-success-text/20 bg-status-success-bg/30'\n : 'border-status-error-text/20 bg-status-error-bg/30'\n }`}\n >\n {validating && !healthResult ? (\n <Loader2 className=\"w-5 h-5 text-text-secondary animate-spin\" />\n ) : healthResult?.ok ? (\n <CheckCircle2 className=\"w-5 h-5 text-status-success-text\" />\n ) : healthResult ? (\n <XCircle className=\"w-5 h-5 text-status-error-text\" />\n ) : (\n <div className=\"w-5 h-5 rounded-full border-2 border-border-default\" />\n )}\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.healthCheck', 'Health Check')}\n </p>\n {healthResult?.ok && healthResult.data && (\n <p className=\"text-xs text-text-secondary\">\n Status: {healthResult.data.status} | Version: {healthResult.data.version} |\n Uptime: {Math.round(healthResult.data.uptime)}s\n </p>\n )}\n {healthResult && !healthResult.ok && (\n <p className=\"text-xs text-status-error-text\">{healthResult.error}</p>\n )}\n </div>\n </div>\n\n {/* API Access Check */}\n <div\n className={`flex items-center gap-3 p-3 rounded-lg border ${\n identityResult === null\n ? 'border-border-default bg-bg-sunken'\n : identityResult.ok\n ? 'border-status-success-text/20 bg-status-success-bg/30'\n : 'border-status-error-text/20 bg-status-error-bg/30'\n }`}\n >\n {validating && !identityResult ? (\n <Loader2 className=\"w-5 h-5 text-text-secondary animate-spin\" />\n ) : identityResult?.ok ? (\n <CheckCircle2 className=\"w-5 h-5 text-status-success-text\" />\n ) : identityResult ? (\n <XCircle className=\"w-5 h-5 text-status-error-text\" />\n ) : (\n <div className=\"w-5 h-5 rounded-full border-2 border-border-default\" />\n )}\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.apiAccess', 'API Access')}\n </p>\n {identityResult?.ok && identityResult.data && (\n <p className=\"text-xs text-text-secondary\">\n Host: {identityResult.data.hostname} | {identityResult.data.platform} /{' '}\n {identityResult.data.arch}\n </p>\n )}\n {identityResult && !identityResult.ok && (\n <p className=\"text-xs text-status-error-text\">{identityResult.error}</p>\n )}\n </div>\n </div>\n </div>\n\n {/* Retry button */}\n {!validating && (!healthResult?.ok || !identityResult?.ok) && (\n <button\n type=\"button\"\n onClick={validateAgent}\n className=\"flex items-center gap-2 px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n <RefreshCw className=\"w-3.5 h-3.5\" />\n {tr('agentsPage.retryValidation', 'Retry validation')}\n </button>\n )}\n\n {/* Detected info (editable overrides) */}\n {isValidationPassed && (\n <div className=\"space-y-3 pt-2\">\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('agentsPage.detectedAgentInfo', 'Detected Agent Info')}\n </p>\n\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('agentsPage.name', 'Name')}\n </label>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={detectedHostname}\n className=\"w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('agentsPage.platform', 'Platform')}\n </label>\n <select\n value={detectedPlatform}\n onChange={(e) => setDetectedPlatform(e.target.value)}\n className=\"w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value=\"linux\">Linux</option>\n <option value=\"darwin\">macOS</option>\n <option value=\"windows\">Windows</option>\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('agentsPage.architecture', 'Architecture')}\n </label>\n <select\n value={detectedArch}\n onChange={(e) => setDetectedArch(e.target.value)}\n className=\"w-full px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n >\n <option value=\"x86_64\">x86_64</option>\n <option value=\"arm64\">arm64</option>\n <option value=\"aarch64\">aarch64</option>\n </select>\n </div>\n </div>\n </div>\n )}\n\n {/* Creation error */}\n {createError && (\n <div className=\"p-3 bg-status-error-bg/30 border border-status-error-text/20 rounded-lg\">\n <div className=\"flex items-center gap-2\">\n <XCircle className=\"w-5 h-5 text-status-error-text flex-shrink-0\" />\n <p className=\"text-sm text-status-error-text\">{createError}</p>\n </div>\n <div className=\"flex items-center gap-2 mt-3\">\n <button\n type=\"button\"\n onClick={() => {\n setCreateError(null);\n // Reset form to allow entering different credentials\n setStage('details');\n setTunnelUrl('');\n setAgentApiKey('');\n setHealthResult(null);\n setIdentityResult(null);\n }}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n <RefreshCw className=\"w-3.5 h-3.5\" />\n {tr('agentsPage.tryDifferentAgent', 'Try Different Agent')}\n </button>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-3 py-1.5 text-sm font-medium text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr('agentsPage.close', 'Close')}\n </button>\n </div>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex items-center justify-between pt-4\">\n <button\n type=\"button\"\n onClick={() => setStage('details')}\n className=\"flex items-center gap-1 px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n <ChevronLeft className=\"w-4 h-4\" />\n {tr('agentsPage.back', 'Back')}\n </button>\n <button\n type=\"button\"\n disabled={!isValidationPassed || isLoading || validating}\n onClick={handleCreateAgent}\n className=\"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 disabled:opacity-50\"\n >\n {isLoading ? (\n <>\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n {tr('agentsPage.adding', 'Adding...')}\n </>\n ) : (\n <>\n {tr('agentsPage.addAgent', 'Add Agent')}\n <ChevronRight className=\"w-4 h-4\" />\n </>\n )}\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|