@burdenoff/microfe-vibecontrols 2026.613.1 → 2026.618.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.
- package/dist/components/agents/AgentConnectionRecovery.js +100 -94
- package/dist/components/agents/AgentConnectionRecovery.js.map +1 -1
- package/dist/components/agents/AgentMaintenanceTab.js +177 -160
- package/dist/components/agents/AgentMaintenanceTab.js.map +1 -1
- package/dist/components/agents/OpenInBrowserEditorButton.js +102 -94
- package/dist/components/agents/OpenInBrowserEditorButton.js.map +1 -1
- package/dist/components/assistant/AssistantChatArea.js +1 -0
- package/dist/components/assistant/AssistantChatArea.js.map +1 -1
- package/dist/components/assistant/AssistantModeSelector.js +20 -19
- package/dist/components/assistant/AssistantModeSelector.js.map +1 -1
- package/dist/components/tunnels/TunnelCard.js +3 -3
- package/dist/components/tunnels/TunnelCard.js.map +1 -1
- package/dist/components/tunnels/TunnelPublicAccessPanel.js +36 -36
- package/dist/components/tunnels/TunnelPublicAccessPanel.js.map +1 -1
- package/dist/config/assistantUsecases.js +11 -0
- package/dist/config/assistantUsecases.js.map +1 -1
- package/dist/constants/permissions.js +38 -6
- package/dist/constants/permissions.js.map +1 -1
- package/dist/index.js +4 -3
- package/dist/pages/CatalogDetailPage.js +155 -155
- package/dist/pages/CatalogDetailPage.js.map +1 -1
- package/dist/pages/CatalogPage.js +110 -109
- package/dist/pages/CatalogPage.js.map +1 -1
- package/dist/pages/ComponentDetailPage.js +338 -338
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/ComponentsPage.js +104 -103
- package/dist/pages/ComponentsPage.js.map +1 -1
- package/dist/pages/TargetDetailsPage.js +140 -132
- package/dist/pages/TargetDetailsPage.js.map +1 -1
- package/dist/pages/TemplateDetailPage.js +201 -199
- package/dist/pages/TemplateDetailPage.js.map +1 -1
- package/dist/pages/TemplatesPage.js +62 -61
- package/dist/pages/TemplatesPage.js.map +1 -1
- package/dist/pages/VibeDetailsPage.js +568 -555
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/ai/AIBookmarksPage.js +104 -89
- package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
- package/dist/pages/ai/AIPage.js +116 -107
- package/dist/pages/ai/AIPage.js.map +1 -1
- package/dist/pages/ai/AISessionDetailPage.js +46 -34
- package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
- package/dist/pages/ai/AgentManagerPage.js +112 -100
- package/dist/pages/ai/AgentManagerPage.js.map +1 -1
- package/dist/pages/tunnels/TunnelDetailsPage.js +177 -153
- package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
- package/dist/pages/tunnels/TunnelsTab.js +119 -111
- package/dist/pages/tunnels/TunnelsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelDomainsTab.js +24 -24
- package/dist/pages/tunnels/tabs/TunnelDomainsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +9 -8
- package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelSessionsTab.js +13 -13
- package/dist/pages/tunnels/tabs/TunnelSessionsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +19 -15
- package/dist/pages/tunnels/tabs/TunnelSettingsTab.js.map +1 -1
- package/dist/services/assistantApi.js +9 -3
- package/dist/services/assistantApi.js.map +1 -1
- package/dist/services/createSandboxAssistantTransport.js +120 -0
- package/dist/services/createSandboxAssistantTransport.js.map +1 -0
- package/dist/store/assistantStore.js +1 -1
- package/dist/store/assistantStore.js.map +1 -1
- package/package.json +5 -1
|
@@ -1,179 +1,185 @@
|
|
|
1
1
|
import { useSetAgentApiKeyMutation as e, useUpdateAgentTunnelUrlMutation as t } from "../../generated/wspace-operations.js";
|
|
2
2
|
import { useTr as n } from "../../shared/hooks/useTr.js";
|
|
3
3
|
import { useField as r } from "../../shared/hooks/useField.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { VIBE_PERMISSIONS as i } from "../../constants/permissions.js";
|
|
5
|
+
import { useState as a } from "react";
|
|
6
|
+
import { AlertTriangle as o, Eye as s, EyeOff as c, KeyRound as l, Link2 as u, Loader2 as d, ShieldCheck as f } from "lucide-react";
|
|
7
|
+
import { usePermissions as p } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
8
|
+
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
7
9
|
//#region src/components/agents/AgentConnectionRecovery.tsx
|
|
8
|
-
var
|
|
9
|
-
function
|
|
10
|
+
var g = "rounded-card border border-border-default bg-bg-surface p-4", _ = "inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-button bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bgHover transition-colors disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus", v = "w-full px-3 py-2 text-base md:text-sm rounded-input bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-border-focus font-mono", y = "mb-1 block text-xs font-medium text-text-muted";
|
|
11
|
+
function b(e) {
|
|
10
12
|
return e instanceof Error ? e.message : String(e);
|
|
11
13
|
}
|
|
12
|
-
function
|
|
13
|
-
let
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
function x({ agentId: x, currentTunnelUrl: S, onUpdated: C }) {
|
|
15
|
+
let w = n(), { hasPermission: T } = p(), E = T(i.AGENT_ADMIN), [D, O] = a(""), [k, A] = a(!1), [j, { loading: M }] = e(), [N, P] = a(null), F = r(), I = async () => {
|
|
16
|
+
if (!E) return;
|
|
17
|
+
P(null);
|
|
18
|
+
let e = D.trim();
|
|
16
19
|
if (e) try {
|
|
17
|
-
await
|
|
18
|
-
agentId:
|
|
20
|
+
await j({ variables: {
|
|
21
|
+
agentId: x,
|
|
19
22
|
apiKey: e
|
|
20
|
-
} }),
|
|
23
|
+
} }), P({
|
|
21
24
|
ok: !0,
|
|
22
|
-
msg:
|
|
23
|
-
}),
|
|
25
|
+
msg: w("agentDetails.recovery.keySaved", "API key validated and saved. The agent is reachable again.")
|
|
26
|
+
}), O(""), C?.();
|
|
24
27
|
} catch (e) {
|
|
25
|
-
|
|
28
|
+
P({
|
|
26
29
|
ok: !1,
|
|
27
|
-
msg:
|
|
30
|
+
msg: b(e)
|
|
28
31
|
});
|
|
29
32
|
}
|
|
30
|
-
}, [
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
}, [L, R] = a(S ?? ""), [z, { loading: B }] = t(), [V, H] = a(null), U = r(), W = async () => {
|
|
34
|
+
if (!E) return;
|
|
35
|
+
H(null);
|
|
36
|
+
let e = L.trim();
|
|
33
37
|
if (e) try {
|
|
34
|
-
await
|
|
35
|
-
agentId:
|
|
38
|
+
await z({ variables: {
|
|
39
|
+
agentId: x,
|
|
36
40
|
tunnelUrl: e
|
|
37
|
-
} }),
|
|
41
|
+
} }), H({
|
|
38
42
|
ok: !0,
|
|
39
|
-
msg:
|
|
40
|
-
}),
|
|
43
|
+
msg: w("agentDetails.recovery.urlSaved", "Tunnel URL verified and updated. The agent is back online.")
|
|
44
|
+
}), C?.();
|
|
41
45
|
} catch (e) {
|
|
42
|
-
|
|
46
|
+
H({
|
|
43
47
|
ok: !1,
|
|
44
|
-
msg:
|
|
48
|
+
msg: b(e)
|
|
45
49
|
});
|
|
46
50
|
}
|
|
47
|
-
},
|
|
51
|
+
}, G = (e) => e ? /* @__PURE__ */ h("p", {
|
|
48
52
|
role: "status",
|
|
49
53
|
className: `mt-2 flex items-start gap-2 text-xs ${e.ok ? "text-status-success-text" : "text-status-error-text"}`,
|
|
50
|
-
children: [e.ok ? /* @__PURE__ */ f
|
|
54
|
+
children: [e.ok ? /* @__PURE__ */ m(f, {
|
|
51
55
|
className: "size-4 flex-shrink-0 mt-0.5",
|
|
52
56
|
"aria-hidden": "true"
|
|
53
|
-
}) : /* @__PURE__ */
|
|
57
|
+
}) : /* @__PURE__ */ m(o, {
|
|
54
58
|
className: "size-4 flex-shrink-0 mt-0.5",
|
|
55
59
|
"aria-hidden": "true"
|
|
56
|
-
}), /* @__PURE__ */
|
|
60
|
+
}), /* @__PURE__ */ m("span", { children: e.msg })]
|
|
57
61
|
}) : null;
|
|
58
|
-
return /* @__PURE__ */
|
|
62
|
+
return /* @__PURE__ */ h("div", {
|
|
59
63
|
className: "space-y-4",
|
|
60
|
-
children: [/* @__PURE__ */
|
|
61
|
-
className:
|
|
64
|
+
children: [/* @__PURE__ */ h("section", {
|
|
65
|
+
className: g,
|
|
62
66
|
children: [
|
|
63
|
-
/* @__PURE__ */
|
|
67
|
+
/* @__PURE__ */ h("div", {
|
|
64
68
|
className: "flex items-center gap-2 mb-1",
|
|
65
|
-
children: [/* @__PURE__ */
|
|
69
|
+
children: [/* @__PURE__ */ m(l, {
|
|
66
70
|
className: "size-5 text-text-secondary",
|
|
67
71
|
"aria-hidden": "true"
|
|
68
|
-
}), /* @__PURE__ */
|
|
72
|
+
}), /* @__PURE__ */ m("h3", {
|
|
69
73
|
className: "text-base font-semibold text-text-primary",
|
|
70
|
-
children:
|
|
74
|
+
children: w("agentDetails.recovery.keyTitle", "Update API key (no re-add)")
|
|
71
75
|
})]
|
|
72
76
|
}),
|
|
73
|
-
/* @__PURE__ */
|
|
77
|
+
/* @__PURE__ */ m("p", {
|
|
74
78
|
className: "text-xs text-text-muted mb-3",
|
|
75
|
-
children:
|
|
79
|
+
children: w("agentDetails.recovery.keyHint", "If the agent’s API key changed and it can’t auto-report (gateway auth down), paste the value from `vibe key` on the host. It’s validated against the agent before saving — your sessions and data stay intact.")
|
|
76
80
|
}),
|
|
77
|
-
/* @__PURE__ */
|
|
81
|
+
/* @__PURE__ */ h("div", {
|
|
78
82
|
className: "flex flex-col sm:flex-row sm:items-end gap-2",
|
|
79
|
-
children: [/* @__PURE__ */
|
|
83
|
+
children: [/* @__PURE__ */ h("div", {
|
|
80
84
|
className: "flex-1 min-w-0",
|
|
81
|
-
children: [/* @__PURE__ */
|
|
82
|
-
htmlFor:
|
|
83
|
-
className:
|
|
84
|
-
children:
|
|
85
|
-
}), /* @__PURE__ */
|
|
85
|
+
children: [/* @__PURE__ */ m("label", {
|
|
86
|
+
htmlFor: F.id,
|
|
87
|
+
className: y,
|
|
88
|
+
children: w("agentDetails.recovery.keyLabel", "Agent API key")
|
|
89
|
+
}), /* @__PURE__ */ h("div", {
|
|
86
90
|
className: "relative",
|
|
87
|
-
children: [/* @__PURE__ */
|
|
88
|
-
...
|
|
89
|
-
type:
|
|
91
|
+
children: [/* @__PURE__ */ m("input", {
|
|
92
|
+
...F.inputProps,
|
|
93
|
+
type: k ? "text" : "password",
|
|
90
94
|
autoComplete: "off",
|
|
91
|
-
value:
|
|
92
|
-
onChange: (e) =>
|
|
95
|
+
value: D,
|
|
96
|
+
onChange: (e) => O(e.target.value),
|
|
93
97
|
placeholder: "vcak_…",
|
|
94
|
-
className: `${
|
|
95
|
-
}), /* @__PURE__ */
|
|
98
|
+
className: `${v} pr-10`
|
|
99
|
+
}), /* @__PURE__ */ m("button", {
|
|
96
100
|
type: "button",
|
|
97
|
-
onClick: () =>
|
|
98
|
-
"aria-label":
|
|
101
|
+
onClick: () => A((e) => !e),
|
|
102
|
+
"aria-label": k ? w("agentDetails.recovery.hideKey", "Hide API key") : w("agentDetails.recovery.showKey", "Show API key"),
|
|
99
103
|
className: "absolute right-1 top-1/2 -translate-y-1/2 inline-flex size-8 items-center justify-center rounded-button text-text-muted transition-colors hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
100
|
-
children:
|
|
104
|
+
children: m(k ? c : s, {
|
|
101
105
|
className: "size-4",
|
|
102
106
|
"aria-hidden": "true"
|
|
103
107
|
})
|
|
104
108
|
})]
|
|
105
109
|
})]
|
|
106
|
-
}), /* @__PURE__ */
|
|
110
|
+
}), /* @__PURE__ */ h("button", {
|
|
107
111
|
type: "button",
|
|
108
|
-
onClick:
|
|
109
|
-
disabled:
|
|
110
|
-
"
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
onClick: I,
|
|
113
|
+
disabled: M || D.trim().length === 0 || !E,
|
|
114
|
+
title: E ? void 0 : w("common.noPermission", "You do not have permission"),
|
|
115
|
+
"aria-busy": M,
|
|
116
|
+
className: `${_} shrink-0`,
|
|
117
|
+
children: [M ? /* @__PURE__ */ m(d, {
|
|
113
118
|
className: "size-4 animate-spin",
|
|
114
119
|
"aria-hidden": "true"
|
|
115
|
-
}) : /* @__PURE__ */ f
|
|
120
|
+
}) : /* @__PURE__ */ m(f, {
|
|
116
121
|
className: "size-4",
|
|
117
122
|
"aria-hidden": "true"
|
|
118
|
-
}),
|
|
123
|
+
}), w("agentDetails.recovery.validateSave", "Validate & save")]
|
|
119
124
|
})]
|
|
120
125
|
}),
|
|
121
|
-
|
|
126
|
+
G(N)
|
|
122
127
|
]
|
|
123
|
-
}), /* @__PURE__ */
|
|
124
|
-
className:
|
|
128
|
+
}), /* @__PURE__ */ h("section", {
|
|
129
|
+
className: g,
|
|
125
130
|
children: [
|
|
126
|
-
/* @__PURE__ */
|
|
131
|
+
/* @__PURE__ */ h("div", {
|
|
127
132
|
className: "flex items-center gap-2 mb-1",
|
|
128
|
-
children: [/* @__PURE__ */
|
|
133
|
+
children: [/* @__PURE__ */ m(u, {
|
|
129
134
|
className: "size-5 text-text-secondary",
|
|
130
135
|
"aria-hidden": "true"
|
|
131
|
-
}), /* @__PURE__ */
|
|
136
|
+
}), /* @__PURE__ */ m("h3", {
|
|
132
137
|
className: "text-base font-semibold text-text-primary",
|
|
133
|
-
children:
|
|
138
|
+
children: w("agentDetails.recovery.urlTitle", "Update tunnel URL (re-pair)")
|
|
134
139
|
})]
|
|
135
140
|
}),
|
|
136
|
-
/* @__PURE__ */
|
|
141
|
+
/* @__PURE__ */ m("p", {
|
|
137
142
|
className: "text-xs text-text-muted mb-3",
|
|
138
|
-
children:
|
|
143
|
+
children: w("agentDetails.recovery.urlHint", "After a quick-tunnel rotation, paste the new URL here. The backend verifies it points at the same machine before saving — no re-registration, no data loss.")
|
|
139
144
|
}),
|
|
140
|
-
/* @__PURE__ */
|
|
145
|
+
/* @__PURE__ */ h("div", {
|
|
141
146
|
className: "flex flex-col sm:flex-row sm:items-end gap-2",
|
|
142
|
-
children: [/* @__PURE__ */
|
|
147
|
+
children: [/* @__PURE__ */ h("div", {
|
|
143
148
|
className: "flex-1 min-w-0",
|
|
144
|
-
children: [/* @__PURE__ */
|
|
145
|
-
htmlFor:
|
|
146
|
-
className:
|
|
147
|
-
children:
|
|
148
|
-
}), /* @__PURE__ */
|
|
149
|
-
...
|
|
149
|
+
children: [/* @__PURE__ */ m("label", {
|
|
150
|
+
htmlFor: U.id,
|
|
151
|
+
className: y,
|
|
152
|
+
children: w("agentDetails.recovery.urlLabel", "Tunnel URL")
|
|
153
|
+
}), /* @__PURE__ */ m("input", {
|
|
154
|
+
...U.inputProps,
|
|
150
155
|
type: "url",
|
|
151
|
-
value:
|
|
152
|
-
onChange: (e) =>
|
|
156
|
+
value: L,
|
|
157
|
+
onChange: (e) => R(e.target.value),
|
|
153
158
|
placeholder: "https://….trycloudflare.com",
|
|
154
|
-
className:
|
|
159
|
+
className: v
|
|
155
160
|
})]
|
|
156
|
-
}), /* @__PURE__ */
|
|
161
|
+
}), /* @__PURE__ */ h("button", {
|
|
157
162
|
type: "button",
|
|
158
|
-
onClick:
|
|
159
|
-
disabled:
|
|
160
|
-
"
|
|
161
|
-
|
|
162
|
-
|
|
163
|
+
onClick: W,
|
|
164
|
+
disabled: B || L.trim().length === 0 || !E,
|
|
165
|
+
title: E ? void 0 : w("common.noPermission", "You do not have permission"),
|
|
166
|
+
"aria-busy": B,
|
|
167
|
+
className: `${_} shrink-0`,
|
|
168
|
+
children: [B ? /* @__PURE__ */ m(d, {
|
|
163
169
|
className: "size-4 animate-spin",
|
|
164
170
|
"aria-hidden": "true"
|
|
165
|
-
}) : /* @__PURE__ */
|
|
171
|
+
}) : /* @__PURE__ */ m(u, {
|
|
166
172
|
className: "size-4",
|
|
167
173
|
"aria-hidden": "true"
|
|
168
|
-
}),
|
|
174
|
+
}), w("agentDetails.recovery.verifyUpdate", "Verify & update")]
|
|
169
175
|
})]
|
|
170
176
|
}),
|
|
171
|
-
V
|
|
177
|
+
G(V)
|
|
172
178
|
]
|
|
173
179
|
})]
|
|
174
180
|
});
|
|
175
181
|
}
|
|
176
182
|
//#endregion
|
|
177
|
-
export {
|
|
183
|
+
export { x as AgentConnectionRecovery };
|
|
178
184
|
|
|
179
185
|
//# sourceMappingURL=AgentConnectionRecovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentConnectionRecovery.js","names":[],"sources":["../../../src/components/agents/AgentConnectionRecovery.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { Eye, EyeOff, KeyRound, Link2, Loader2, ShieldCheck, AlertTriangle } from 'lucide-react';\n\nimport {\n useSetAgentApiKeyMutation,\n useUpdateAgentTunnelUrlMutation,\n} from '@/generated/wspace-operations';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { useField } from '../../shared/hooks/useField';\n\ninterface AgentConnectionRecoveryProps {\n agentId: string;\n currentTunnelUrl?: string | null;\n /** Refetch the agent after a successful in-place update. */\n onUpdated?: () => void;\n}\n\nconst CARD = 'rounded-card border border-border-default bg-bg-surface p-4';\nconst BTN =\n 'inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-button bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bgHover transition-colors disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus';\nconst INPUT =\n 'w-full px-3 py-2 text-base md:text-sm rounded-input bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-border-focus font-mono';\nconst LABEL = 'mb-1 block text-xs font-medium text-text-muted';\n\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/**\n * Emergency connection recovery for an existing agent — used when gateway\n * auto-report is broken (so the agent can't refresh its own key/tunnel) and\n * the operator must fix it in place WITHOUT delete + re-add (which loses\n * sessions / notes / bookmarks).\n * - \"Update API key\": paste the value from `vibe key`; the backend probes the\n * agent with it and only saves if the agent accepts it.\n * - \"Update tunnel URL\": paste the new quick-tunnel URL; the backend verifies\n * it's the same machine (hostname) before saving.\n */\nexport function AgentConnectionRecovery({\n agentId,\n currentTunnelUrl,\n onUpdated,\n}: AgentConnectionRecoveryProps) {\n const tr = useTr();\n\n // ── API key ─────────────────────────────────────────────────────────────\n const [keyInput, setKeyInput] = useState('');\n const [showKey, setShowKey] = useState(false);\n const [setKey, { loading: settingKey }] = useSetAgentApiKeyMutation();\n const [keyResult, setKeyResult] = useState<{ ok: boolean; msg: string } | null>(null);\n const keyField = useField();\n\n const handleSetKey = async () => {\n setKeyResult(null);\n const key = keyInput.trim();\n if (!key) return;\n try {\n await setKey({ variables: { agentId, apiKey: key } });\n setKeyResult({\n ok: true,\n msg: tr(\n 'agentDetails.recovery.keySaved',\n 'API key validated and saved. The agent is reachable again.'\n ),\n });\n setKeyInput('');\n onUpdated?.();\n } catch (e) {\n setKeyResult({ ok: false, msg: errMsg(e) });\n }\n };\n\n // ── Tunnel URL ──────────────────────────────────────────────────────────\n const [urlInput, setUrlInput] = useState(currentTunnelUrl ?? '');\n const [updateUrl, { loading: updatingUrl }] = useUpdateAgentTunnelUrlMutation();\n const [urlResult, setUrlResult] = useState<{ ok: boolean; msg: string } | null>(null);\n const urlField = useField();\n\n const handleUpdateUrl = async () => {\n setUrlResult(null);\n const url = urlInput.trim();\n if (!url) return;\n try {\n await updateUrl({ variables: { agentId, tunnelUrl: url } });\n setUrlResult({\n ok: true,\n msg: tr(\n 'agentDetails.recovery.urlSaved',\n 'Tunnel URL verified and updated. The agent is back online.'\n ),\n });\n onUpdated?.();\n } catch (e) {\n setUrlResult({ ok: false, msg: errMsg(e) });\n }\n };\n\n const result = (r: { ok: boolean; msg: string } | null) =>\n r ? (\n <p\n role=\"status\"\n className={`mt-2 flex items-start gap-2 text-xs ${\n r.ok ? 'text-status-success-text' : 'text-status-error-text'\n }`}\n >\n {r.ok ? (\n <ShieldCheck className=\"size-4 flex-shrink-0 mt-0.5\" aria-hidden=\"true\" />\n ) : (\n <AlertTriangle className=\"size-4 flex-shrink-0 mt-0.5\" aria-hidden=\"true\" />\n )}\n <span>{r.msg}</span>\n </p>\n ) : null;\n\n return (\n <div className=\"space-y-4\">\n <section className={CARD}>\n <div className=\"flex items-center gap-2 mb-1\">\n <KeyRound className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('agentDetails.recovery.keyTitle', 'Update API key (no re-add)')}\n </h3>\n </div>\n <p className=\"text-xs text-text-muted mb-3\">\n {tr(\n 'agentDetails.recovery.keyHint',\n 'If the agent’s API key changed and it can’t auto-report (gateway auth down), paste the value from `vibe key` on the host. It’s validated against the agent before saving — your sessions and data stay intact.'\n )}\n </p>\n <div className=\"flex flex-col sm:flex-row sm:items-end gap-2\">\n <div className=\"flex-1 min-w-0\">\n <label htmlFor={keyField.id} className={LABEL}>\n {tr('agentDetails.recovery.keyLabel', 'Agent API key')}\n </label>\n <div className=\"relative\">\n <input\n {...keyField.inputProps}\n type={showKey ? 'text' : 'password'}\n autoComplete=\"off\"\n value={keyInput}\n onChange={(e) => setKeyInput(e.target.value)}\n placeholder=\"vcak_…\"\n className={`${INPUT} pr-10`}\n />\n <button\n type=\"button\"\n onClick={() => setShowKey((v) => !v)}\n aria-label={\n showKey\n ? tr('agentDetails.recovery.hideKey', 'Hide API key')\n : tr('agentDetails.recovery.showKey', 'Show API key')\n }\n className=\"absolute right-1 top-1/2 -translate-y-1/2 inline-flex size-8 items-center justify-center rounded-button text-text-muted transition-colors hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n >\n {showKey ? (\n <EyeOff className=\"size-4\" aria-hidden=\"true\" />\n ) : (\n <Eye className=\"size-4\" aria-hidden=\"true\" />\n )}\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={handleSetKey}\n disabled={settingKey || keyInput.trim().length === 0}\n aria-busy={settingKey}\n className={`${BTN} shrink-0`}\n >\n {settingKey ? (\n <Loader2 className=\"size-4 animate-spin\" aria-hidden=\"true\" />\n ) : (\n <ShieldCheck className=\"size-4\" aria-hidden=\"true\" />\n )}\n {tr('agentDetails.recovery.validateSave', 'Validate & save')}\n </button>\n </div>\n {result(keyResult)}\n </section>\n\n <section className={CARD}>\n <div className=\"flex items-center gap-2 mb-1\">\n <Link2 className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('agentDetails.recovery.urlTitle', 'Update tunnel URL (re-pair)')}\n </h3>\n </div>\n <p className=\"text-xs text-text-muted mb-3\">\n {tr(\n 'agentDetails.recovery.urlHint',\n 'After a quick-tunnel rotation, paste the new URL here. The backend verifies it points at the same machine before saving — no re-registration, no data loss.'\n )}\n </p>\n <div className=\"flex flex-col sm:flex-row sm:items-end gap-2\">\n <div className=\"flex-1 min-w-0\">\n <label htmlFor={urlField.id} className={LABEL}>\n {tr('agentDetails.recovery.urlLabel', 'Tunnel URL')}\n </label>\n <input\n {...urlField.inputProps}\n type=\"url\"\n value={urlInput}\n onChange={(e) => setUrlInput(e.target.value)}\n placeholder=\"https://….trycloudflare.com\"\n className={INPUT}\n />\n </div>\n <button\n type=\"button\"\n onClick={handleUpdateUrl}\n disabled={updatingUrl || urlInput.trim().length === 0}\n aria-busy={updatingUrl}\n className={`${BTN} shrink-0`}\n >\n {updatingUrl ? (\n <Loader2 className=\"size-4 animate-spin\" aria-hidden=\"true\" />\n ) : (\n <Link2 className=\"size-4\" aria-hidden=\"true\" />\n )}\n {tr('agentDetails.recovery.verifyUpdate', 'Verify & update')}\n </button>\n </div>\n {result(urlResult)}\n </section>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AgentConnectionRecovery.js","names":[],"sources":["../../../src/components/agents/AgentConnectionRecovery.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { Eye, EyeOff, KeyRound, Link2, Loader2, ShieldCheck, AlertTriangle } from 'lucide-react';\n\nimport {\n useSetAgentApiKeyMutation,\n useUpdateAgentTunnelUrlMutation,\n} from '@/generated/wspace-operations';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { useField } from '../../shared/hooks/useField';\n\ninterface AgentConnectionRecoveryProps {\n agentId: string;\n currentTunnelUrl?: string | null;\n /** Refetch the agent after a successful in-place update. */\n onUpdated?: () => void;\n}\n\nconst CARD = 'rounded-card border border-border-default bg-bg-surface p-4';\nconst BTN =\n 'inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-button bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bgHover transition-colors disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus';\nconst INPUT =\n 'w-full px-3 py-2 text-base md:text-sm rounded-input bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-border-focus font-mono';\nconst LABEL = 'mb-1 block text-xs font-medium text-text-muted';\n\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/**\n * Emergency connection recovery for an existing agent — used when gateway\n * auto-report is broken (so the agent can't refresh its own key/tunnel) and\n * the operator must fix it in place WITHOUT delete + re-add (which loses\n * sessions / notes / bookmarks).\n * - \"Update API key\": paste the value from `vibe key`; the backend probes the\n * agent with it and only saves if the agent accepts it.\n * - \"Update tunnel URL\": paste the new quick-tunnel URL; the backend verifies\n * it's the same machine (hostname) before saving.\n */\nexport function AgentConnectionRecovery({\n agentId,\n currentTunnelUrl,\n onUpdated,\n}: AgentConnectionRecoveryProps) {\n const tr = useTr();\n // API-key recovery and tunnel-URL recovery are both enforced as `agent:admin`\n // at the gateway.\n const { hasPermission } = usePermissions();\n const canAdmin = hasPermission(VIBE_PERMISSIONS.AGENT_ADMIN);\n\n // ── API key ─────────────────────────────────────────────────────────────\n const [keyInput, setKeyInput] = useState('');\n const [showKey, setShowKey] = useState(false);\n const [setKey, { loading: settingKey }] = useSetAgentApiKeyMutation();\n const [keyResult, setKeyResult] = useState<{ ok: boolean; msg: string } | null>(null);\n const keyField = useField();\n\n const handleSetKey = async () => {\n if (!canAdmin) return;\n setKeyResult(null);\n const key = keyInput.trim();\n if (!key) return;\n try {\n await setKey({ variables: { agentId, apiKey: key } });\n setKeyResult({\n ok: true,\n msg: tr(\n 'agentDetails.recovery.keySaved',\n 'API key validated and saved. The agent is reachable again.'\n ),\n });\n setKeyInput('');\n onUpdated?.();\n } catch (e) {\n setKeyResult({ ok: false, msg: errMsg(e) });\n }\n };\n\n // ── Tunnel URL ──────────────────────────────────────────────────────────\n const [urlInput, setUrlInput] = useState(currentTunnelUrl ?? '');\n const [updateUrl, { loading: updatingUrl }] = useUpdateAgentTunnelUrlMutation();\n const [urlResult, setUrlResult] = useState<{ ok: boolean; msg: string } | null>(null);\n const urlField = useField();\n\n const handleUpdateUrl = async () => {\n if (!canAdmin) return;\n setUrlResult(null);\n const url = urlInput.trim();\n if (!url) return;\n try {\n await updateUrl({ variables: { agentId, tunnelUrl: url } });\n setUrlResult({\n ok: true,\n msg: tr(\n 'agentDetails.recovery.urlSaved',\n 'Tunnel URL verified and updated. The agent is back online.'\n ),\n });\n onUpdated?.();\n } catch (e) {\n setUrlResult({ ok: false, msg: errMsg(e) });\n }\n };\n\n const result = (r: { ok: boolean; msg: string } | null) =>\n r ? (\n <p\n role=\"status\"\n className={`mt-2 flex items-start gap-2 text-xs ${\n r.ok ? 'text-status-success-text' : 'text-status-error-text'\n }`}\n >\n {r.ok ? (\n <ShieldCheck className=\"size-4 flex-shrink-0 mt-0.5\" aria-hidden=\"true\" />\n ) : (\n <AlertTriangle className=\"size-4 flex-shrink-0 mt-0.5\" aria-hidden=\"true\" />\n )}\n <span>{r.msg}</span>\n </p>\n ) : null;\n\n return (\n <div className=\"space-y-4\">\n <section className={CARD}>\n <div className=\"flex items-center gap-2 mb-1\">\n <KeyRound className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('agentDetails.recovery.keyTitle', 'Update API key (no re-add)')}\n </h3>\n </div>\n <p className=\"text-xs text-text-muted mb-3\">\n {tr(\n 'agentDetails.recovery.keyHint',\n 'If the agent’s API key changed and it can’t auto-report (gateway auth down), paste the value from `vibe key` on the host. It’s validated against the agent before saving — your sessions and data stay intact.'\n )}\n </p>\n <div className=\"flex flex-col sm:flex-row sm:items-end gap-2\">\n <div className=\"flex-1 min-w-0\">\n <label htmlFor={keyField.id} className={LABEL}>\n {tr('agentDetails.recovery.keyLabel', 'Agent API key')}\n </label>\n <div className=\"relative\">\n <input\n {...keyField.inputProps}\n type={showKey ? 'text' : 'password'}\n autoComplete=\"off\"\n value={keyInput}\n onChange={(e) => setKeyInput(e.target.value)}\n placeholder=\"vcak_…\"\n className={`${INPUT} pr-10`}\n />\n <button\n type=\"button\"\n onClick={() => setShowKey((v) => !v)}\n aria-label={\n showKey\n ? tr('agentDetails.recovery.hideKey', 'Hide API key')\n : tr('agentDetails.recovery.showKey', 'Show API key')\n }\n className=\"absolute right-1 top-1/2 -translate-y-1/2 inline-flex size-8 items-center justify-center rounded-button text-text-muted transition-colors hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n >\n {showKey ? (\n <EyeOff className=\"size-4\" aria-hidden=\"true\" />\n ) : (\n <Eye className=\"size-4\" aria-hidden=\"true\" />\n )}\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={handleSetKey}\n disabled={settingKey || keyInput.trim().length === 0 || !canAdmin}\n title={canAdmin ? undefined : tr('common.noPermission', 'You do not have permission')}\n aria-busy={settingKey}\n className={`${BTN} shrink-0`}\n >\n {settingKey ? (\n <Loader2 className=\"size-4 animate-spin\" aria-hidden=\"true\" />\n ) : (\n <ShieldCheck className=\"size-4\" aria-hidden=\"true\" />\n )}\n {tr('agentDetails.recovery.validateSave', 'Validate & save')}\n </button>\n </div>\n {result(keyResult)}\n </section>\n\n <section className={CARD}>\n <div className=\"flex items-center gap-2 mb-1\">\n <Link2 className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('agentDetails.recovery.urlTitle', 'Update tunnel URL (re-pair)')}\n </h3>\n </div>\n <p className=\"text-xs text-text-muted mb-3\">\n {tr(\n 'agentDetails.recovery.urlHint',\n 'After a quick-tunnel rotation, paste the new URL here. The backend verifies it points at the same machine before saving — no re-registration, no data loss.'\n )}\n </p>\n <div className=\"flex flex-col sm:flex-row sm:items-end gap-2\">\n <div className=\"flex-1 min-w-0\">\n <label htmlFor={urlField.id} className={LABEL}>\n {tr('agentDetails.recovery.urlLabel', 'Tunnel URL')}\n </label>\n <input\n {...urlField.inputProps}\n type=\"url\"\n value={urlInput}\n onChange={(e) => setUrlInput(e.target.value)}\n placeholder=\"https://….trycloudflare.com\"\n className={INPUT}\n />\n </div>\n <button\n type=\"button\"\n onClick={handleUpdateUrl}\n disabled={updatingUrl || urlInput.trim().length === 0 || !canAdmin}\n title={canAdmin ? undefined : tr('common.noPermission', 'You do not have permission')}\n aria-busy={updatingUrl}\n className={`${BTN} shrink-0`}\n >\n {updatingUrl ? (\n <Loader2 className=\"size-4 animate-spin\" aria-hidden=\"true\" />\n ) : (\n <Link2 className=\"size-4\" aria-hidden=\"true\" />\n )}\n {tr('agentDetails.recovery.verifyUpdate', 'Verify & update')}\n </button>\n </div>\n {result(urlResult)}\n </section>\n </div>\n );\n}\n"],"mappings":"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"}
|