@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.
Files changed (62) hide show
  1. package/dist/components/agents/AgentConnectionRecovery.js +100 -94
  2. package/dist/components/agents/AgentConnectionRecovery.js.map +1 -1
  3. package/dist/components/agents/AgentMaintenanceTab.js +177 -160
  4. package/dist/components/agents/AgentMaintenanceTab.js.map +1 -1
  5. package/dist/components/agents/OpenInBrowserEditorButton.js +102 -94
  6. package/dist/components/agents/OpenInBrowserEditorButton.js.map +1 -1
  7. package/dist/components/assistant/AssistantChatArea.js +1 -0
  8. package/dist/components/assistant/AssistantChatArea.js.map +1 -1
  9. package/dist/components/assistant/AssistantModeSelector.js +20 -19
  10. package/dist/components/assistant/AssistantModeSelector.js.map +1 -1
  11. package/dist/components/tunnels/TunnelCard.js +3 -3
  12. package/dist/components/tunnels/TunnelCard.js.map +1 -1
  13. package/dist/components/tunnels/TunnelPublicAccessPanel.js +36 -36
  14. package/dist/components/tunnels/TunnelPublicAccessPanel.js.map +1 -1
  15. package/dist/config/assistantUsecases.js +11 -0
  16. package/dist/config/assistantUsecases.js.map +1 -1
  17. package/dist/constants/permissions.js +38 -6
  18. package/dist/constants/permissions.js.map +1 -1
  19. package/dist/index.js +4 -3
  20. package/dist/pages/CatalogDetailPage.js +155 -155
  21. package/dist/pages/CatalogDetailPage.js.map +1 -1
  22. package/dist/pages/CatalogPage.js +110 -109
  23. package/dist/pages/CatalogPage.js.map +1 -1
  24. package/dist/pages/ComponentDetailPage.js +338 -338
  25. package/dist/pages/ComponentDetailPage.js.map +1 -1
  26. package/dist/pages/ComponentsPage.js +104 -103
  27. package/dist/pages/ComponentsPage.js.map +1 -1
  28. package/dist/pages/TargetDetailsPage.js +140 -132
  29. package/dist/pages/TargetDetailsPage.js.map +1 -1
  30. package/dist/pages/TemplateDetailPage.js +201 -199
  31. package/dist/pages/TemplateDetailPage.js.map +1 -1
  32. package/dist/pages/TemplatesPage.js +62 -61
  33. package/dist/pages/TemplatesPage.js.map +1 -1
  34. package/dist/pages/VibeDetailsPage.js +568 -555
  35. package/dist/pages/VibeDetailsPage.js.map +1 -1
  36. package/dist/pages/ai/AIBookmarksPage.js +104 -89
  37. package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
  38. package/dist/pages/ai/AIPage.js +116 -107
  39. package/dist/pages/ai/AIPage.js.map +1 -1
  40. package/dist/pages/ai/AISessionDetailPage.js +46 -34
  41. package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
  42. package/dist/pages/ai/AgentManagerPage.js +112 -100
  43. package/dist/pages/ai/AgentManagerPage.js.map +1 -1
  44. package/dist/pages/tunnels/TunnelDetailsPage.js +177 -153
  45. package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
  46. package/dist/pages/tunnels/TunnelsTab.js +119 -111
  47. package/dist/pages/tunnels/TunnelsTab.js.map +1 -1
  48. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js +24 -24
  49. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js.map +1 -1
  50. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +9 -8
  51. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
  52. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js +13 -13
  53. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js.map +1 -1
  54. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +19 -15
  55. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js.map +1 -1
  56. package/dist/services/assistantApi.js +9 -3
  57. package/dist/services/assistantApi.js.map +1 -1
  58. package/dist/services/createSandboxAssistantTransport.js +120 -0
  59. package/dist/services/createSandboxAssistantTransport.js.map +1 -0
  60. package/dist/store/assistantStore.js +1 -1
  61. package/dist/store/assistantStore.js.map +1 -1
  62. 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 { useState as i } from "react";
5
- import { AlertTriangle as a, Eye as o, EyeOff as s, KeyRound as c, Link2 as l, Loader2 as u, ShieldCheck as d } from "lucide-react";
6
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
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 m = "rounded-card border border-border-default bg-bg-surface p-4", h = "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", g = "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", _ = "mb-1 block text-xs font-medium text-text-muted";
9
- function v(e) {
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 y({ agentId: y, currentTunnelUrl: b, onUpdated: x }) {
13
- let S = n(), [C, w] = i(""), [T, E] = i(!1), [D, { loading: O }] = e(), [k, A] = i(null), j = r(), M = async () => {
14
- A(null);
15
- let e = C.trim();
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 D({ variables: {
18
- agentId: y,
20
+ await j({ variables: {
21
+ agentId: x,
19
22
  apiKey: e
20
- } }), A({
23
+ } }), P({
21
24
  ok: !0,
22
- msg: S("agentDetails.recovery.keySaved", "API key validated and saved. The agent is reachable again.")
23
- }), w(""), x?.();
25
+ msg: w("agentDetails.recovery.keySaved", "API key validated and saved. The agent is reachable again.")
26
+ }), O(""), C?.();
24
27
  } catch (e) {
25
- A({
28
+ P({
26
29
  ok: !1,
27
- msg: v(e)
30
+ msg: b(e)
28
31
  });
29
32
  }
30
- }, [N, P] = i(b ?? ""), [F, { loading: I }] = t(), [L, R] = i(null), z = r(), B = async () => {
31
- R(null);
32
- let e = N.trim();
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 F({ variables: {
35
- agentId: y,
38
+ await z({ variables: {
39
+ agentId: x,
36
40
  tunnelUrl: e
37
- } }), R({
41
+ } }), H({
38
42
  ok: !0,
39
- msg: S("agentDetails.recovery.urlSaved", "Tunnel URL verified and updated. The agent is back online.")
40
- }), x?.();
43
+ msg: w("agentDetails.recovery.urlSaved", "Tunnel URL verified and updated. The agent is back online.")
44
+ }), C?.();
41
45
  } catch (e) {
42
- R({
46
+ H({
43
47
  ok: !1,
44
- msg: v(e)
48
+ msg: b(e)
45
49
  });
46
50
  }
47
- }, V = (e) => e ? /* @__PURE__ */ p("p", {
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(d, {
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__ */ f(a, {
57
+ }) : /* @__PURE__ */ m(o, {
54
58
  className: "size-4 flex-shrink-0 mt-0.5",
55
59
  "aria-hidden": "true"
56
- }), /* @__PURE__ */ f("span", { children: e.msg })]
60
+ }), /* @__PURE__ */ m("span", { children: e.msg })]
57
61
  }) : null;
58
- return /* @__PURE__ */ p("div", {
62
+ return /* @__PURE__ */ h("div", {
59
63
  className: "space-y-4",
60
- children: [/* @__PURE__ */ p("section", {
61
- className: m,
64
+ children: [/* @__PURE__ */ h("section", {
65
+ className: g,
62
66
  children: [
63
- /* @__PURE__ */ p("div", {
67
+ /* @__PURE__ */ h("div", {
64
68
  className: "flex items-center gap-2 mb-1",
65
- children: [/* @__PURE__ */ f(c, {
69
+ children: [/* @__PURE__ */ m(l, {
66
70
  className: "size-5 text-text-secondary",
67
71
  "aria-hidden": "true"
68
- }), /* @__PURE__ */ f("h3", {
72
+ }), /* @__PURE__ */ m("h3", {
69
73
  className: "text-base font-semibold text-text-primary",
70
- children: S("agentDetails.recovery.keyTitle", "Update API key (no re-add)")
74
+ children: w("agentDetails.recovery.keyTitle", "Update API key (no re-add)")
71
75
  })]
72
76
  }),
73
- /* @__PURE__ */ f("p", {
77
+ /* @__PURE__ */ m("p", {
74
78
  className: "text-xs text-text-muted mb-3",
75
- children: S("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.")
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__ */ p("div", {
81
+ /* @__PURE__ */ h("div", {
78
82
  className: "flex flex-col sm:flex-row sm:items-end gap-2",
79
- children: [/* @__PURE__ */ p("div", {
83
+ children: [/* @__PURE__ */ h("div", {
80
84
  className: "flex-1 min-w-0",
81
- children: [/* @__PURE__ */ f("label", {
82
- htmlFor: j.id,
83
- className: _,
84
- children: S("agentDetails.recovery.keyLabel", "Agent API key")
85
- }), /* @__PURE__ */ p("div", {
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__ */ f("input", {
88
- ...j.inputProps,
89
- type: T ? "text" : "password",
91
+ children: [/* @__PURE__ */ m("input", {
92
+ ...F.inputProps,
93
+ type: k ? "text" : "password",
90
94
  autoComplete: "off",
91
- value: C,
92
- onChange: (e) => w(e.target.value),
95
+ value: D,
96
+ onChange: (e) => O(e.target.value),
93
97
  placeholder: "vcak_…",
94
- className: `${g} pr-10`
95
- }), /* @__PURE__ */ f("button", {
98
+ className: `${v} pr-10`
99
+ }), /* @__PURE__ */ m("button", {
96
100
  type: "button",
97
- onClick: () => E((e) => !e),
98
- "aria-label": T ? S("agentDetails.recovery.hideKey", "Hide API key") : S("agentDetails.recovery.showKey", "Show API key"),
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: f(T ? s : o, {
104
+ children: m(k ? c : s, {
101
105
  className: "size-4",
102
106
  "aria-hidden": "true"
103
107
  })
104
108
  })]
105
109
  })]
106
- }), /* @__PURE__ */ p("button", {
110
+ }), /* @__PURE__ */ h("button", {
107
111
  type: "button",
108
- onClick: M,
109
- disabled: O || C.trim().length === 0,
110
- "aria-busy": O,
111
- className: `${h} shrink-0`,
112
- children: [O ? /* @__PURE__ */ f(u, {
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(d, {
120
+ }) : /* @__PURE__ */ m(f, {
116
121
  className: "size-4",
117
122
  "aria-hidden": "true"
118
- }), S("agentDetails.recovery.validateSave", "Validate & save")]
123
+ }), w("agentDetails.recovery.validateSave", "Validate & save")]
119
124
  })]
120
125
  }),
121
- V(k)
126
+ G(N)
122
127
  ]
123
- }), /* @__PURE__ */ p("section", {
124
- className: m,
128
+ }), /* @__PURE__ */ h("section", {
129
+ className: g,
125
130
  children: [
126
- /* @__PURE__ */ p("div", {
131
+ /* @__PURE__ */ h("div", {
127
132
  className: "flex items-center gap-2 mb-1",
128
- children: [/* @__PURE__ */ f(l, {
133
+ children: [/* @__PURE__ */ m(u, {
129
134
  className: "size-5 text-text-secondary",
130
135
  "aria-hidden": "true"
131
- }), /* @__PURE__ */ f("h3", {
136
+ }), /* @__PURE__ */ m("h3", {
132
137
  className: "text-base font-semibold text-text-primary",
133
- children: S("agentDetails.recovery.urlTitle", "Update tunnel URL (re-pair)")
138
+ children: w("agentDetails.recovery.urlTitle", "Update tunnel URL (re-pair)")
134
139
  })]
135
140
  }),
136
- /* @__PURE__ */ f("p", {
141
+ /* @__PURE__ */ m("p", {
137
142
  className: "text-xs text-text-muted mb-3",
138
- children: S("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.")
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__ */ p("div", {
145
+ /* @__PURE__ */ h("div", {
141
146
  className: "flex flex-col sm:flex-row sm:items-end gap-2",
142
- children: [/* @__PURE__ */ p("div", {
147
+ children: [/* @__PURE__ */ h("div", {
143
148
  className: "flex-1 min-w-0",
144
- children: [/* @__PURE__ */ f("label", {
145
- htmlFor: z.id,
146
- className: _,
147
- children: S("agentDetails.recovery.urlLabel", "Tunnel URL")
148
- }), /* @__PURE__ */ f("input", {
149
- ...z.inputProps,
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: N,
152
- onChange: (e) => P(e.target.value),
156
+ value: L,
157
+ onChange: (e) => R(e.target.value),
153
158
  placeholder: "https://….trycloudflare.com",
154
- className: g
159
+ className: v
155
160
  })]
156
- }), /* @__PURE__ */ p("button", {
161
+ }), /* @__PURE__ */ h("button", {
157
162
  type: "button",
158
- onClick: B,
159
- disabled: I || N.trim().length === 0,
160
- "aria-busy": I,
161
- className: `${h} shrink-0`,
162
- children: [I ? /* @__PURE__ */ f(u, {
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__ */ f(l, {
171
+ }) : /* @__PURE__ */ m(u, {
166
172
  className: "size-4",
167
173
  "aria-hidden": "true"
168
- }), S("agentDetails.recovery.verifyUpdate", "Verify & update")]
174
+ }), w("agentDetails.recovery.verifyUpdate", "Verify & update")]
169
175
  })]
170
176
  }),
171
- V(L)
177
+ G(V)
172
178
  ]
173
179
  })]
174
180
  });
175
181
  }
176
182
  //#endregion
177
- export { y as AgentConnectionRecovery };
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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"}