@openagt/servers 0.0.1 → 0.0.3

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,54 +1,58 @@
1
- import { Button as e, Checkbox as t, Input as n, SettingsSection as r, defineModule as i, useModuleHost as a, usePolled as o } from "@openagt/dashboard/module";
2
- import { useEffect as s, useRef as c, useState as l } from "react";
3
- import { jsx as u, jsxs as d } from "react/jsx-runtime";
1
+ import { Button as e, Checkbox as t, Input as n, QrCode as r, SettingsSection as i, defineModule as a, useModuleHost as o, usePolled as s } from "@openagt/dashboard/module";
2
+ import { useEffect as c, useRef as l, useState as u } from "react";
3
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
4
4
  //#region dashboard/servers.ts
5
- var f = (e) => typeof e == "string" && e ? e : void 0, p = [
5
+ var p = (e) => typeof e == "string" && e ? e : void 0, m = [
6
6
  "waiting",
7
7
  "running",
8
8
  "done",
9
9
  "failed"
10
10
  ];
11
- function m(e) {
12
- let { there: t, working: n, asking: r, wanted: i, account: a, since: o, ends: s, said: c } = e && typeof e == "object" ? e : {}, [l, u, d, p] = [
13
- f(a),
14
- f(o),
15
- f(s),
16
- f(c)
11
+ function h(e) {
12
+ let { there: t, working: n, asking: r, code: i, wanted: a, account: o, since: s, ends: c, said: l } = e && typeof e == "object" ? e : {}, [u, d, f, m, h] = [
13
+ p(o),
14
+ p(s),
15
+ p(c),
16
+ p(l),
17
+ p(i)
17
18
  ];
18
19
  return {
19
20
  there: t === !0,
20
21
  working: n === !0,
21
- ...r === !0 ? { asking: !0 } : {},
22
- ...i === !0 ? { wanted: !0 } : {},
23
- ...l ? { account: l } : {},
24
- ...u ? { since: u } : {},
25
- ...d ? { ends: d } : {},
26
- ...p ? { said: p } : {}
22
+ ...r === !0 ? {
23
+ asking: !0,
24
+ ...h ? { code: h } : {}
25
+ } : {},
26
+ ...a === !0 ? { wanted: !0 } : {},
27
+ ...u ? { account: u } : {},
28
+ ...d ? { since: d } : {},
29
+ ...f ? { ends: f } : {},
30
+ ...m ? { said: m } : {}
27
31
  };
28
32
  }
29
- function h(e) {
33
+ function g(e) {
30
34
  if (!e || typeof e != "object") return;
31
35
  let { servers: t } = e;
32
36
  if (!Array.isArray(t)) return;
33
37
  let n = [];
34
38
  for (let e of t) {
35
39
  if (!e || typeof e != "object") continue;
36
- let { address: t, url: r, user: i, fingerprint: a, working: o, adding: s, steps: c, logins: l } = e, { github: u, claude: d } = l && typeof l == "object" ? l : {}, [h, g, _, v] = [
37
- f(t),
38
- f(r),
39
- f(i),
40
- f(a)
40
+ let { address: t, url: r, user: i, fingerprint: a, working: o, adding: s, steps: c, logins: l } = e, { github: u, claude: d } = l && typeof l == "object" ? l : {}, [f, g, _, v] = [
41
+ p(t),
42
+ p(r),
43
+ p(i),
44
+ p(a)
41
45
  ];
42
- if (!h || !g || !_ || !Array.isArray(c)) continue;
46
+ if (!f || !g || !_ || !Array.isArray(c)) continue;
43
47
  let y = [];
44
48
  for (let e of c) {
45
49
  if (!e || typeof e != "object") continue;
46
50
  let { id: t, label: n, state: r, said: i } = e, [a, o, s] = [
47
- f(t),
48
- f(n),
49
- f(i)
51
+ p(t),
52
+ p(n),
53
+ p(i)
50
54
  ];
51
- a && o && p.includes(r) && y.push({
55
+ a && o && m.includes(r) && y.push({
52
56
  id: a,
53
57
  label: o,
54
58
  state: r,
@@ -56,7 +60,7 @@ function h(e) {
56
60
  });
57
61
  }
58
62
  n.push({
59
- address: h,
63
+ address: f,
60
64
  url: g,
61
65
  user: _,
62
66
  ...v ? { fingerprint: v } : {},
@@ -64,99 +68,98 @@ function h(e) {
64
68
  adding: s === !0,
65
69
  steps: y,
66
70
  logins: {
67
- github: m(u),
68
- claude: m(d)
71
+ github: h(u),
72
+ claude: h(d)
69
73
  }
70
74
  });
71
75
  }
72
76
  return n;
73
77
  }
74
- function g(e) {
78
+ function _(e) {
75
79
  if (!e || typeof e != "object") return;
76
- let { url: t, expires: n } = e, [r, i] = [f(t), f(n)];
80
+ let { url: t, expires: n } = e, [r, i] = [p(t), p(n)];
77
81
  return r && i ? {
78
82
  url: r,
79
83
  expires: i
80
84
  } : void 0;
81
85
  }
82
- async function _(e, t, n, r) {
83
- let i = {
86
+ async function v(e, t, n) {
87
+ let r = await e.runComputerCommand(t).catch((e) => ({
84
88
  ok: !1,
85
- error: "no project to run the command in"
89
+ error: e instanceof Error ? e.message : String(e)
90
+ }));
91
+ if (!r.ok) return r;
92
+ let i = n(r.output);
93
+ return i === void 0 ? {
94
+ ok: !1,
95
+ error: "the command answered something else than expected"
96
+ } : {
97
+ ok: !0,
98
+ value: i
99
+ };
100
+ }
101
+ function y(e) {
102
+ let t = g(e);
103
+ return t && {
104
+ servers: t,
105
+ isServer: e.server === !0
86
106
  };
87
- for (let [a, o] of t.entries()) {
88
- let t = await e.runCommand(o.id, n).catch((e) => ({
89
- ok: !1,
90
- error: e instanceof Error ? e.message : String(e)
91
- }));
92
- if (t.ok) {
93
- let e = r(t.output);
94
- return e === void 0 ? {
95
- ok: !1,
96
- error: "the command answered something else than expected"
97
- } : {
98
- ok: !0,
99
- value: e
100
- };
101
- }
102
- a === 0 && (i = t);
103
- }
104
- return i;
105
107
  }
106
- var v = (e, t) => _(e, t, ["status"], h), y = (e, t, n, r, i, a = !1) => _(e, t, [
108
+ var b = (e) => v(e, ["status"], y), x = (e, t, n, r, i = !1) => v(e, [
107
109
  "connect",
110
+ t,
108
111
  n,
109
112
  r,
110
- i,
111
- ...a ? ["github"] : []
112
- ], h);
113
- function b(e) {
113
+ ...i ? ["github"] : []
114
+ ], g);
115
+ function S(e) {
114
116
  if (!e || typeof e != "object") return;
115
- let { account: t, problem: n } = e, [r, i] = [f(t), f(n)];
117
+ let { account: t, problem: n } = e, [r, i] = [p(t), p(n)];
116
118
  return r ? { account: r } : i ? { problem: i } : void 0;
117
119
  }
118
- var ee = (e, t) => _(e, t, ["github"], b), x = (e, t, n, r) => _(e, t, [
120
+ var ee = (e) => v(e, ["github"], S), C = (e, t, n, r = !1) => v(e, [
119
121
  "login",
122
+ t,
120
123
  n,
121
- r
122
- ], h), S = (e, t, n, r) => _(e, t, [
124
+ ...r ? ["own"] : []
125
+ ], g), w = (e, t, n) => v(e, [
123
126
  "logout",
124
- n,
125
- r
126
- ], h), C = (e, t, n) => _(e, t, ["link", n], g), w = (e, t, n) => _(e, t, ["added", n], h), T = (e, t, n) => _(e, t, ["forget", n], h), E = void 0, te = void 0, ne = void 0, D = (e) => e === void 0 ? "" : new Date(e).toLocaleDateString(void 0, {
127
+ t,
128
+ n
129
+ ], g), T = (e, t) => v(e, ["link", t], _), te = (e, t) => v(e, ["added", t], g), ne = (e, t) => v(e, ["forget", t], g), E = void 0, D = 5 * 6e4, O = void 0, k = void 0, A = (e) => e === void 0 ? "" : new Date(e).toLocaleDateString(void 0, {
127
130
  day: "numeric",
128
131
  month: "short",
129
132
  year: "numeric"
130
133
  });
131
- function O({ label: e, words: t, said: n, children: r }) {
132
- return /* @__PURE__ */ d("li", {
134
+ function j({ label: e, words: t, said: n, children: r }) {
135
+ return /* @__PURE__ */ f("li", {
133
136
  "aria-label": e,
134
137
  className: "space-y-1",
135
- children: [/* @__PURE__ */ d("div", {
138
+ children: [/* @__PURE__ */ f("div", {
136
139
  className: "flex flex-wrap items-center justify-between gap-2",
137
- children: [/* @__PURE__ */ u("span", { children: t }), /* @__PURE__ */ u("div", {
140
+ children: [/* @__PURE__ */ d("span", { children: t }), /* @__PURE__ */ d("div", {
138
141
  className: "flex gap-2",
139
142
  children: r
140
143
  })]
141
- }), n !== void 0 && /* @__PURE__ */ u("pre", {
144
+ }), n !== void 0 && /* @__PURE__ */ d("pre", {
142
145
  role: "alert",
143
146
  className: "overflow-x-auto whitespace-pre-wrap rounded-md border border-border bg-background p-2 font-mono text-foreground",
144
147
  children: n
145
148
  })]
146
149
  });
147
150
  }
148
- var k = {
151
+ var M = {
149
152
  waiting: "○",
150
153
  running: "…",
151
154
  done: "✓",
152
155
  failed: "✕"
153
- }, re = {
156
+ }, N = {
154
157
  waiting: "not started",
155
158
  running: "running",
156
159
  done: "done",
157
160
  failed: "failed"
158
- }, A = (e, t) => Object.fromEntries(Object.entries(e).filter(([e]) => e !== t));
159
- function j(e, t) {
161
+ }, P = (e, t) => Object.fromEntries(Object.entries(e).filter(([e]) => e !== t));
162
+ function F(e, t) {
160
163
  let n = (e) => {
161
164
  let t = /^(\d+)\.(\d+)\.(\d+)/.exec(e);
162
165
  return t ? t.slice(1).map(Number) : void 0;
@@ -165,244 +168,321 @@ function j(e, t) {
165
168
  for (let e = 0; e < 3; e++) if (r[e] !== i[e]) return r[e] < i[e];
166
169
  return !1;
167
170
  }
168
- function M({ projects: i, everyMs: f = 3e3 }) {
169
- let p = a(), m = i.map((e) => e.id).join(","), { value: h, reload: g } = o(() => v(p, i), E, f, [m]), { value: _, reload: b } = o(() => p.machines(), te, Math.max(f, 1e4), []), { value: M } = o(() => ee(p, i), ne, Math.max(f, 5 * 6e4), [m]), N = M?.ok && "account" in M.value ? M.value.account : void 0, P = M === void 0 || N !== void 0 ? void 0 : M.ok ? "problem" in M.value ? M.value.problem : void 0 : M.error, [F, I] = l(""), [L, R] = l("root"), [z, B] = l(!1), [V, H] = l(!1), [U, W] = l(), [G, K] = l({}), q = c(/* @__PURE__ */ new Set()), J = h?.ok ? h.value : [], Y = (e, t = _) => t?.machines.find((t) => t.url === e.url), X = (e) => !e.working && e.steps.every((e) => e.state === "done"), Z = async (e) => {
170
- H(!0), W(void 0);
171
+ function I({ everyMs: e = 3e3 }) {
172
+ let t = o(), { value: n, reload: r } = s(() => b(t), E, e, []), i = l(void 0);
173
+ return n?.ok && (i.current = n.value.isServer), n === void 0 || i.current === !0 ? null : /* @__PURE__ */ d(L, {
174
+ read: n,
175
+ reload: r,
176
+ everyMs: e
177
+ });
178
+ }
179
+ function L({ read: a, reload: p, everyMs: m }) {
180
+ let h = o(), { value: g, reload: _ } = s(() => h.machines(), O, Math.max(m, 1e4), []), { value: v } = s(() => ee(h), k, Math.max(m, 5 * 6e4), []), y = v?.ok && "account" in v.value ? v.value.account : void 0, b = v === void 0 || y !== void 0 ? void 0 : v.ok ? "problem" in v.value ? v.value.problem : void 0 : v.error, [S, E] = u(""), [I, L] = u("root"), [R, re] = u(!1), [z, B] = u(!1), [V, H] = u(), [U, W] = u({}), G = l(/* @__PURE__ */ new Set()), [K, q] = u(), J = a.ok ? a.value.servers : [], Y = (e, t = g) => t?.machines.find((t) => t.url === e.url), X = (e) => !e.working && e.steps.every((e) => e.state === "done"), Z = async (e) => {
181
+ B(!0), H(void 0);
171
182
  let t = await e();
172
- return t.ok || W(t.error), await g().catch(() => {}), H(!1), t.ok;
173
- }, Q = async (e, t, n = !1) => !_ || _.version === "unknown" ? (W("This computer could not say which OpenAgent it runs."), !1) : (K((t) => A(t, e)), Z(() => y(p, i, e, t, _.version, n))), $ = async (e) => {
174
- if (q.current.has(e.address)) return;
175
- q.current.add(e.address), K((t) => A(t, e.address));
176
- let t = (t) => K((n) => ({
183
+ return t.ok || H(t.error), await p().catch(() => {}), B(!1), t.ok;
184
+ }, Q = async (e, t, n = !1) => !g || g.version === "unknown" ? (H("This computer could not say which OpenAgent it runs."), !1) : (W((t) => P(t, e)), Z(() => x(h, e, t, g.version, n))), $ = async (e) => {
185
+ if (G.current.has(e.address)) return;
186
+ G.current.add(e.address), W((t) => P(t, e.address));
187
+ let t = (t) => W((n) => ({
177
188
  ...n,
178
189
  [e.address]: t
179
190
  }));
180
191
  try {
181
- if (Y(e, await p.machines())?.version === void 0) {
182
- let n = await C(p, i, e.address), r = n.ok ? await p.addMachine(n.value.url, e.address) : n;
192
+ if (Y(e, await h.machines())?.version === void 0) {
193
+ let n = await T(h, e.address), r = n.ok ? await h.addMachine(n.value.url, e.address) : n;
183
194
  if (!r.ok) return t(r.error);
184
195
  }
185
- let n = await w(p, i, e.address);
196
+ let n = await te(h, e.address);
186
197
  if (!n.ok) return t(n.error);
187
- await Promise.all([g(), b()]).catch(() => {});
198
+ await Promise.all([p(), _()]).catch(() => {});
188
199
  } catch (e) {
189
200
  t(e instanceof Error ? e.message : String(e));
190
201
  } finally {
191
- q.current.delete(e.address);
202
+ G.current.delete(e.address);
192
203
  }
193
204
  };
194
- return s(() => {
195
- if (_) for (let e of J) e.adding && X(e) && G[e.address] === void 0 && $(e);
196
- }), i.length === 0 ? null : /* @__PURE__ */ d(r, {
205
+ c(() => {
206
+ if (g) for (let e of J) e.adding && X(e) && U[e.address] === void 0 && $(e);
207
+ }), c(() => {
208
+ if (!K) return;
209
+ let e = setTimeout(() => q(void 0), Math.min(D, Math.max(0, Date.parse(K.expires) - Date.now())));
210
+ return () => clearTimeout(e);
211
+ }, [K]);
212
+ let ie = async (e) => {
213
+ B(!0), H(void 0), q(void 0);
214
+ let t = await T(h, e.address);
215
+ t.ok ? q({
216
+ ...t.value,
217
+ address: e.address
218
+ }) : H(t.error), B(!1);
219
+ };
220
+ return /* @__PURE__ */ f(i, {
197
221
  title: "Servers",
198
222
  description: "Connect your VPS: give its address and a user name, and OpenAgent installs itself there over SSH, with this computer's own SSH keys. The server then runs OpenAgent by itself, and is one of your machines.",
199
223
  children: [
200
- /* @__PURE__ */ d("form", {
224
+ /* @__PURE__ */ f("form", {
201
225
  onSubmit: (e) => {
202
- e.preventDefault(), !(!F.trim() || !L.trim()) && Q(F.trim(), L.trim(), z && N !== void 0).then((e) => e && I(""));
226
+ e.preventDefault(), !(!S.trim() || !I.trim()) && Q(S.trim(), I.trim(), R && y !== void 0).then((e) => e && E(""));
203
227
  },
204
228
  className: "flex flex-wrap items-end gap-2 py-3",
205
229
  children: [
206
- /* @__PURE__ */ d("label", {
230
+ /* @__PURE__ */ f("label", {
207
231
  className: "min-w-40 flex-1 space-y-1 text-xs text-muted-foreground",
208
- children: [/* @__PURE__ */ u("span", { children: "The server's address" }), /* @__PURE__ */ u(n, {
232
+ children: [/* @__PURE__ */ d("span", { children: "The server's address" }), /* @__PURE__ */ d(n, {
209
233
  "aria-label": "The server's address",
210
234
  placeholder: "203.0.113.5",
211
- value: F,
212
- onChange: (e) => I(e.target.value)
235
+ value: S,
236
+ onChange: (e) => E(e.target.value)
213
237
  })]
214
238
  }),
215
- /* @__PURE__ */ d("label", {
239
+ /* @__PURE__ */ f("label", {
216
240
  className: "w-32 space-y-1 text-xs text-muted-foreground",
217
- children: [/* @__PURE__ */ u("span", { children: "User name" }), /* @__PURE__ */ u(n, {
241
+ children: [/* @__PURE__ */ d("span", { children: "User name" }), /* @__PURE__ */ d(n, {
218
242
  "aria-label": "User name",
219
- value: L,
220
- onChange: (e) => R(e.target.value)
243
+ value: I,
244
+ onChange: (e) => L(e.target.value)
221
245
  })]
222
246
  }),
223
- /* @__PURE__ */ u(e, {
247
+ /* @__PURE__ */ d(e, {
224
248
  size: "sm",
225
249
  type: "submit",
226
- disabled: V || !_ || !F.trim() || !L.trim(),
250
+ disabled: z || !g || !S.trim() || !I.trim(),
227
251
  children: "Connect"
228
252
  })
229
253
  ]
230
254
  }),
231
- /* @__PURE__ */ d("div", {
255
+ /* @__PURE__ */ f("div", {
232
256
  className: "space-y-2 pb-3",
233
- children: [/* @__PURE__ */ d("label", {
257
+ children: [/* @__PURE__ */ f("label", {
234
258
  className: "flex items-start gap-2 text-xs",
235
- children: [/* @__PURE__ */ u(t, {
236
- checked: z && N !== void 0,
237
- onCheckedChange: (e) => B(e === !0),
238
- disabled: V || N === void 0,
259
+ children: [/* @__PURE__ */ d(t, {
260
+ checked: R && y !== void 0,
261
+ onCheckedChange: (e) => re(e === !0),
262
+ disabled: z || y === void 0,
239
263
  className: "mt-0.5",
240
264
  "aria-label": "Copy my GitHub login to the server"
241
- }), /* @__PURE__ */ d("span", { children: [
242
- N === void 0 ? "Copy my GitHub login to the server." : `Copy my GitHub login (${N}) to the server.`,
265
+ }), /* @__PURE__ */ f("span", { children: [
266
+ y === void 0 ? "Copy my GitHub login to the server." : `Copy my GitHub login (${y}) to the server.`,
243
267
  " ",
244
- /* @__PURE__ */ u("span", {
268
+ /* @__PURE__ */ d("span", {
245
269
  className: "text-muted-foreground",
246
- children: P ?? "It can do there all it can do here, and every agent that runs on the server works with it. It goes there at the install's end, to a server met for the first time too, whose key is taken as it is."
270
+ children: b ?? "It can do there all it can do here, and every agent that runs on the server works with it. It goes there at the install's end, to a server met for the first time too, whose key is taken as it is."
247
271
  })
248
272
  ] })]
249
- }), /* @__PURE__ */ u("p", {
273
+ }), /* @__PURE__ */ d("p", {
250
274
  className: "text-xs text-muted-foreground",
251
275
  children: "The user is root, or one that becomes root without a password. It is only used to install, to update and to give the server its logins: what runs on the server afterwards runs as a user of its own, openagent."
252
276
  })]
253
277
  }),
254
- J.length > 0 && /* @__PURE__ */ u("ul", {
278
+ J.length > 0 && /* @__PURE__ */ d("ul", {
255
279
  "aria-label": "Servers",
256
280
  className: "divide-y divide-border",
257
281
  children: J.map((t) => {
258
- let n = Y(t), r = !t.working && t.steps.some((e) => e.state === "failed"), a = n?.version !== void 0 && _ !== void 0 && j(n.version, _.version), o = G[t.address], { github: s, claude: c } = t.logins;
259
- return /* @__PURE__ */ d("li", {
282
+ let n = Y(t), i = !t.working && t.steps.some((e) => e.state === "failed"), a = n?.version !== void 0 && g !== void 0 && F(n.version, g.version), o = !t.working && !i && t.steps.some((e) => e.state === "waiting"), s = U[t.address], { github: c, claude: l } = t.logins;
283
+ return /* @__PURE__ */ f("li", {
260
284
  "aria-label": t.address,
261
285
  className: "space-y-2 py-3",
262
286
  children: [
263
- /* @__PURE__ */ d("div", {
287
+ /* @__PURE__ */ f("div", {
264
288
  className: "flex flex-wrap items-center justify-between gap-2",
265
- children: [/* @__PURE__ */ d("div", {
289
+ children: [/* @__PURE__ */ f("div", {
266
290
  className: "min-w-0",
267
- children: [/* @__PURE__ */ u("p", {
291
+ children: [/* @__PURE__ */ d("p", {
268
292
  className: "truncate text-sm",
269
293
  children: t.address
270
- }), /* @__PURE__ */ u("p", {
294
+ }), /* @__PURE__ */ d("p", {
271
295
  className: "text-xs text-muted-foreground",
272
- children: t.working ? "OpenAgent is being installed." : n?.version === void 0 ? n ? "Does not answer right now." : X(t) && !t.adding ? "Installed, and not among your machines." : `Logs in as ${t.user}.` : a ? `OpenAgent ${n.version}: behind this computer, which runs ${_.version}.` : `OpenAgent ${n.version}.`
296
+ children: t.working ? "OpenAgent is being installed." : n?.version === void 0 ? n ? "Does not answer right now." : X(t) && !t.adding ? "Installed, and not among your machines." : `Logs in as ${t.user}.` : a ? `OpenAgent ${n.version}: behind this computer, which runs ${g.version}.` : `OpenAgent ${n.version}.`
273
297
  })]
274
- }), /* @__PURE__ */ d("div", {
298
+ }), /* @__PURE__ */ f("div", {
275
299
  className: "flex gap-2",
276
300
  children: [
277
- a && !t.working && !r && /* @__PURE__ */ u(e, {
301
+ (a || o) && !t.working && !i && /* @__PURE__ */ d(e, {
278
302
  size: "sm",
279
- disabled: V,
303
+ disabled: z || !g,
280
304
  "aria-label": `Update ${t.address}`,
281
305
  onClick: () => void Q(t.address, t.user),
282
306
  children: "Update"
283
307
  }),
284
- r && /* @__PURE__ */ u(e, {
308
+ i && /* @__PURE__ */ d(e, {
285
309
  size: "sm",
286
- disabled: V,
310
+ disabled: z || !g,
287
311
  "aria-label": `Try ${t.address} again`,
288
- onClick: () => void Q(t.address, t.user, s.wanted === !0),
312
+ onClick: () => void Q(t.address, t.user, c.wanted === !0),
289
313
  children: "Try again"
290
314
  }),
291
- X(t) && n?.version === void 0 && (o !== void 0 || !t.adding) && /* @__PURE__ */ u(e, {
315
+ X(t) && n?.version === void 0 && (s !== void 0 || !t.adding) && /* @__PURE__ */ d(e, {
292
316
  size: "sm",
293
317
  variant: "outline",
294
- disabled: V,
318
+ disabled: z,
295
319
  "aria-label": `Add ${t.address} to Machines`,
296
320
  onClick: () => void $(t),
297
321
  children: n ? "Add again" : "Add to Machines"
298
322
  }),
299
- !t.working && /* @__PURE__ */ u(e, {
323
+ X(t) && /* @__PURE__ */ d(e, {
324
+ size: "sm",
325
+ variant: "outline",
326
+ disabled: z,
327
+ "aria-label": `Add a device to ${t.address}`,
328
+ onClick: () => void ie(t),
329
+ children: "Add device"
330
+ }),
331
+ !t.working && /* @__PURE__ */ d(e, {
300
332
  size: "sm",
301
333
  variant: "outline",
302
- disabled: V,
334
+ disabled: z,
303
335
  "aria-label": `Remove ${t.address}`,
304
336
  title: "Takes the server off this list. Nothing is changed on the server: its logins stay there until you remove them.",
305
- onClick: () => void Z(() => T(p, i, t.address)),
337
+ onClick: () => void Z(() => ne(h, t.address)),
306
338
  children: "Remove"
307
339
  })
308
340
  ]
309
341
  })]
310
342
  }),
311
- /* @__PURE__ */ d("ol", {
343
+ K?.address === t.address && /* @__PURE__ */ f("div", {
344
+ className: "space-y-2",
345
+ children: [
346
+ /* @__PURE__ */ d(r, {
347
+ text: K.url,
348
+ label: `The code a new device scans to get into ${t.address}`
349
+ }),
350
+ /* @__PURE__ */ d("p", {
351
+ className: "text-xs text-muted-foreground",
352
+ children: "Scan it with the device's camera: it opens OpenAgent on the server, from anywhere. The code works once, for five minutes."
353
+ }),
354
+ /* @__PURE__ */ f("div", {
355
+ className: "flex flex-wrap items-center gap-3",
356
+ children: [/* @__PURE__ */ d("a", {
357
+ href: K.url,
358
+ target: "_blank",
359
+ rel: "noreferrer",
360
+ className: "text-xs underline",
361
+ onClick: () => q(void 0),
362
+ children: "Let this browser in instead"
363
+ }), /* @__PURE__ */ d(e, {
364
+ size: "sm",
365
+ variant: "outline",
366
+ onClick: () => q(void 0),
367
+ children: "Done"
368
+ })]
369
+ })
370
+ ]
371
+ }),
372
+ /* @__PURE__ */ f("ol", {
312
373
  "aria-label": `The install on ${t.address}`,
313
374
  className: "space-y-1 text-xs",
314
375
  children: [
315
- t.steps.map((e) => /* @__PURE__ */ d("li", {
316
- "aria-label": `${e.label}: ${re[e.state]}`,
376
+ t.steps.map((e) => /* @__PURE__ */ f("li", {
377
+ "aria-label": `${e.label}: ${N[e.state]}`,
317
378
  children: [
318
- /* @__PURE__ */ d("span", {
379
+ /* @__PURE__ */ f("span", {
319
380
  className: e.state === "failed" ? "text-danger" : e.state === "waiting" ? "text-muted-foreground" : void 0,
320
- children: [/* @__PURE__ */ u("span", {
381
+ children: [/* @__PURE__ */ d("span", {
321
382
  "aria-hidden": !0,
322
383
  className: "inline-block w-4",
323
- children: k[e.state]
384
+ children: M[e.state]
324
385
  }), e.label]
325
386
  }),
326
- e.id === "login" && e.state === "done" && t.fingerprint !== void 0 && /* @__PURE__ */ u("span", {
387
+ e.id === "login" && e.state === "done" && t.fingerprint !== void 0 && /* @__PURE__ */ d("span", {
327
388
  className: "ml-2 font-mono text-muted-foreground",
328
389
  children: `The server's key: ${t.fingerprint}`
329
390
  }),
330
- e.said !== void 0 && e.state === "failed" && /* @__PURE__ */ u("pre", {
391
+ e.said !== void 0 && e.state === "failed" && /* @__PURE__ */ d("pre", {
331
392
  role: "alert",
332
393
  className: "mt-1 ml-4 overflow-x-auto whitespace-pre-wrap rounded-md border border-border bg-background p-2 font-mono text-foreground",
333
394
  children: e.said
334
395
  })
335
396
  ]
336
397
  }, e.id)),
337
- t.logins.github.working && /* @__PURE__ */ d("li", {
398
+ t.logins.github.working && /* @__PURE__ */ f("li", {
338
399
  "aria-label": "Your GitHub login: not copied yet",
339
400
  className: "text-muted-foreground",
340
- children: [/* @__PURE__ */ u("span", {
401
+ children: [/* @__PURE__ */ d("span", {
341
402
  "aria-hidden": !0,
342
403
  className: "inline-block w-4",
343
- children: k[t.steps.every((e) => e.state === "done") ? "running" : "waiting"]
404
+ children: M[t.steps.every((e) => e.state === "done") ? "running" : "waiting"]
344
405
  }), "Your GitHub login"]
345
406
  }),
346
- X(t) && /* @__PURE__ */ d("li", {
347
- "aria-label": `Among your machines: ${n ? "done" : o === void 0 ? t.adding ? "running" : "not started" : "failed"}`,
348
- children: [/* @__PURE__ */ d("span", {
349
- className: n ? void 0 : o === void 0 ? "text-muted-foreground" : "text-danger",
350
- children: [/* @__PURE__ */ u("span", {
407
+ X(t) && /* @__PURE__ */ f("li", {
408
+ "aria-label": `Among your machines: ${n ? "done" : s === void 0 ? t.adding ? "running" : "not started" : "failed"}`,
409
+ children: [/* @__PURE__ */ f("span", {
410
+ className: n ? void 0 : s === void 0 ? "text-muted-foreground" : "text-danger",
411
+ children: [/* @__PURE__ */ d("span", {
351
412
  "aria-hidden": !0,
352
413
  className: "inline-block w-4",
353
- children: k[n ? "done" : o === void 0 ? t.adding ? "running" : "waiting" : "failed"]
414
+ children: M[n ? "done" : s === void 0 ? t.adding ? "running" : "waiting" : "failed"]
354
415
  }), "Among your machines"]
355
- }), o !== void 0 && !n && /* @__PURE__ */ u("pre", {
416
+ }), s !== void 0 && !n && /* @__PURE__ */ d("pre", {
356
417
  role: "alert",
357
418
  className: "mt-1 ml-4 overflow-x-auto whitespace-pre-wrap rounded-md border border-border bg-background p-2 font-mono text-foreground",
358
- children: o
419
+ children: s
359
420
  })]
360
421
  })
361
422
  ]
362
423
  }),
363
- X(t) && /* @__PURE__ */ d("ul", {
424
+ X(t) && /* @__PURE__ */ f("ul", {
364
425
  "aria-label": `The logins on ${t.address}`,
365
426
  className: "space-y-2 border-t border-border pt-2 text-xs",
366
- children: [/* @__PURE__ */ d(O, {
427
+ children: [/* @__PURE__ */ f(j, {
367
428
  label: "GitHub",
368
- words: s.working ? "GitHub: one moment, the server is being told." : s.there ? `GitHub: logged in as ${s.account ?? "you"} since ${D(s.since)}.` : s.said === void 0 ? "GitHub: no login on the server." : "GitHub: the last try did not go through.",
369
- said: s.working ? void 0 : s.said,
370
- children: [/* @__PURE__ */ u(e, {
371
- size: "sm",
372
- variant: "outline",
373
- disabled: V || s.working || N === void 0,
374
- "aria-label": `Copy my GitHub login to ${t.address}`,
375
- title: N === void 0 ? P : `Copies the login of ${N} from this computer to the server, over SSH.`,
376
- onClick: () => void Z(() => x(p, i, t.address, "github")),
377
- children: s.there ? "Copy again" : "Copy my login"
378
- }), (s.there || s.said !== void 0) && !s.working && /* @__PURE__ */ u(e, {
379
- size: "sm",
380
- variant: "outline",
381
- disabled: V,
382
- "aria-label": `Remove the GitHub login from ${t.address}`,
383
- title: "Deletes the login on the server. The login itself stays good: it is this computer's own. To end it everywhere, take it back on github.com and log this computer's gh in again.",
384
- onClick: () => void Z(() => S(p, i, t.address, "github")),
385
- children: "Remove"
386
- })]
387
- }), /* @__PURE__ */ d(O, {
388
- label: "Claude",
389
- words: c.asking ? "Claude: say yes in the page this computer's browser opened." : c.working ? "Claude: one moment, the server is being told." : c.there ? `Claude: logged in since ${D(c.since)}, good until about ${D(c.ends)}.` : c.said === void 0 ? "Claude: not logged in on the server." : "Claude: the last try did not go through.",
429
+ words: c.asking && c.code !== void 0 ? `GitHub: type the code ${c.code} at github.com/login/device, and say yes there.` : c.working ? "GitHub: one moment, the server is being told." : c.there ? `GitHub: logged in as ${c.account ?? "you"} since ${A(c.since)}.` : c.said === void 0 ? "GitHub: no login on the server." : "GitHub: the last try did not go through.",
390
430
  said: c.working ? void 0 : c.said,
391
- children: [/* @__PURE__ */ u(e, {
431
+ children: [
432
+ /* @__PURE__ */ d(e, {
433
+ size: "sm",
434
+ variant: "outline",
435
+ disabled: z || c.working || y === void 0,
436
+ "aria-label": `Copy my GitHub login to ${t.address}`,
437
+ title: y === void 0 ? b : `Copies the login of ${y} from this computer to the server, over SSH.`,
438
+ onClick: () => void Z(() => C(h, t.address, "github")),
439
+ children: c.there ? "Copy again" : "Copy my login"
440
+ }),
441
+ /* @__PURE__ */ d(e, {
442
+ size: "sm",
443
+ variant: "outline",
444
+ disabled: z || c.working && c.asking !== !0,
445
+ "aria-label": `Log in to GitHub for ${t.address}`,
446
+ title: "The server asks GitHub for a login of its own. GitHub gives a short code: you type it at github.com/login/device and say yes there. This computer's own GitHub login is not touched, and the login the server had is replaced.",
447
+ onClick: () => void Z(() => C(h, t.address, "github", !0)),
448
+ children: c.asking ? "Start over" : "Log in to GitHub"
449
+ }),
450
+ c.asking && c.code !== void 0 && /* @__PURE__ */ d("a", {
451
+ href: "https://github.com/login/device",
452
+ target: "_blank",
453
+ rel: "noreferrer",
454
+ className: "self-center underline",
455
+ children: "Open GitHub"
456
+ }),
457
+ (c.there || c.said !== void 0) && !c.working && /* @__PURE__ */ d(e, {
458
+ size: "sm",
459
+ variant: "outline",
460
+ disabled: z,
461
+ "aria-label": `Remove the GitHub login from ${t.address}`,
462
+ title: "Deletes the login on the server. The login itself is not ended by this: a copied one is this computer's own and stays good. To end one everywhere, take it back on github.com.",
463
+ onClick: () => void Z(() => w(h, t.address, "github")),
464
+ children: "Remove"
465
+ })
466
+ ]
467
+ }), /* @__PURE__ */ f(j, {
468
+ label: "Claude",
469
+ words: l.asking ? "Claude: say yes in the page this computer's browser opened." : l.working ? "Claude: one moment, the server is being told." : l.there ? `Claude: logged in since ${A(l.since)}, good until about ${A(l.ends)}.` : l.said === void 0 ? "Claude: not logged in on the server." : "Claude: the last try did not go through.",
470
+ said: l.working ? void 0 : l.said,
471
+ children: [/* @__PURE__ */ d(e, {
392
472
  size: "sm",
393
- variant: c.there || c.working ? "outline" : "default",
394
- disabled: V || c.working && c.asking !== !0,
473
+ variant: l.there || l.working ? "outline" : "default",
474
+ disabled: z || l.working && l.asking !== !0,
395
475
  "aria-label": `Log in to Claude for ${t.address}`,
396
476
  title: "Opens this computer's browser, where you say yes once. The login is made for this server alone and lasts a year; this computer's own Claude login is not touched.",
397
- onClick: () => void Z(() => x(p, i, t.address, "claude")),
398
- children: c.asking ? "Start over" : c.there ? "Log in again" : "Log in to Claude"
399
- }), (c.there || c.said !== void 0) && !c.working && /* @__PURE__ */ u(e, {
477
+ onClick: () => void Z(() => C(h, t.address, "claude")),
478
+ children: l.asking ? "Start over" : l.there ? "Log in again" : "Log in to Claude"
479
+ }), (l.there || l.said !== void 0) && !l.working && /* @__PURE__ */ d(e, {
400
480
  size: "sm",
401
481
  variant: "outline",
402
- disabled: V,
482
+ disabled: z,
403
483
  "aria-label": `Remove the Claude login from ${t.address}`,
404
484
  title: "Deletes the login on the server and starts OpenAgent there again without it. An agent at work there keeps it until it ends. The login itself stays good until its year is over.",
405
- onClick: () => void Z(() => S(p, i, t.address, "claude")),
485
+ onClick: () => void Z(() => w(h, t.address, "claude")),
406
486
  children: "Remove"
407
487
  })]
408
488
  })]
@@ -411,28 +491,28 @@ function M({ projects: i, everyMs: f = 3e3 }) {
411
491
  }, t.address);
412
492
  })
413
493
  }),
414
- h !== void 0 && !h.ok && /* @__PURE__ */ u("p", {
494
+ !a.ok && /* @__PURE__ */ d("p", {
415
495
  role: "alert",
416
496
  className: "py-3 text-xs text-danger",
417
- children: `The servers could not be read: ${h.error}`
497
+ children: `The servers could not be read: ${a.error}`
418
498
  }),
419
- U !== void 0 && /* @__PURE__ */ u("p", {
499
+ V !== void 0 && /* @__PURE__ */ d("p", {
420
500
  role: "alert",
421
501
  className: "py-3 text-xs text-danger",
422
- children: U
502
+ children: V
423
503
  })
424
504
  ]
425
505
  });
426
506
  }
427
507
  //#endregion
428
508
  //#region dashboard/index.tsx
429
- var N = i({
509
+ var R = a({
430
510
  settings: [{
431
511
  id: "servers",
432
512
  order: 20,
433
- Section: M
513
+ Section: () => /* @__PURE__ */ d(I, {})
434
514
  }],
435
515
  stylesheet: "dashboard.css"
436
516
  });
437
517
  //#endregion
438
- export { N as default };
518
+ export { R as default };