@chrysb/alphaclaw 0.1.3 → 0.1.5
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/lib/public/js/app.js
CHANGED
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
fetchOnboardStatus,
|
|
13
13
|
fetchDashboardUrl,
|
|
14
14
|
updateSyncCron,
|
|
15
|
+
fetchAlphaclawVersion,
|
|
16
|
+
updateAlphaclaw,
|
|
15
17
|
} from "./lib/api.js";
|
|
16
18
|
import { usePolling } from "./hooks/usePolling.js";
|
|
17
19
|
import { Gateway } from "./components/gateway.js";
|
|
@@ -240,6 +242,11 @@ const GeneralTab = ({ onSwitchTab }) => {
|
|
|
240
242
|
function App() {
|
|
241
243
|
const [onboarded, setOnboarded] = useState(null);
|
|
242
244
|
const [tab, setTab] = useState("general");
|
|
245
|
+
const [acVersion, setAcVersion] = useState(null);
|
|
246
|
+
const [acLatest, setAcLatest] = useState(null);
|
|
247
|
+
const [acHasUpdate, setAcHasUpdate] = useState(false);
|
|
248
|
+
const [acUpdating, setAcUpdating] = useState(false);
|
|
249
|
+
const [acDismissed, setAcDismissed] = useState(false);
|
|
243
250
|
|
|
244
251
|
useEffect(() => {
|
|
245
252
|
fetchOnboardStatus()
|
|
@@ -247,6 +254,41 @@ function App() {
|
|
|
247
254
|
.catch(() => setOnboarded(false));
|
|
248
255
|
}, []);
|
|
249
256
|
|
|
257
|
+
useEffect(() => {
|
|
258
|
+
if (!onboarded) return;
|
|
259
|
+
let active = true;
|
|
260
|
+
const check = async () => {
|
|
261
|
+
try {
|
|
262
|
+
const data = await fetchAlphaclawVersion(false);
|
|
263
|
+
if (!active) return;
|
|
264
|
+
setAcVersion(data.currentVersion || null);
|
|
265
|
+
setAcLatest(data.latestVersion || null);
|
|
266
|
+
setAcHasUpdate(!!data.hasUpdate);
|
|
267
|
+
} catch {}
|
|
268
|
+
};
|
|
269
|
+
check();
|
|
270
|
+
const id = setInterval(check, 5 * 60 * 1000);
|
|
271
|
+
return () => { active = false; clearInterval(id); };
|
|
272
|
+
}, [onboarded]);
|
|
273
|
+
|
|
274
|
+
const handleAcUpdate = async () => {
|
|
275
|
+
if (acUpdating) return;
|
|
276
|
+
setAcUpdating(true);
|
|
277
|
+
try {
|
|
278
|
+
const data = await updateAlphaclaw();
|
|
279
|
+
if (data.ok) {
|
|
280
|
+
showToast("AlphaClaw updated — restarting...", "success");
|
|
281
|
+
setTimeout(() => window.location.reload(), 5000);
|
|
282
|
+
} else {
|
|
283
|
+
showToast(data.error || "AlphaClaw update failed", "error");
|
|
284
|
+
setAcUpdating(false);
|
|
285
|
+
}
|
|
286
|
+
} catch (err) {
|
|
287
|
+
showToast(err.message || "Could not update AlphaClaw", "error");
|
|
288
|
+
setAcUpdating(false);
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
|
|
250
292
|
// Still loading onboard status
|
|
251
293
|
if (onboarded === null) {
|
|
252
294
|
return html`
|
|
@@ -288,11 +330,37 @@ function App() {
|
|
|
288
330
|
<div class="flex items-center gap-3 pb-3">
|
|
289
331
|
<div class="text-4xl">🦞</div>
|
|
290
332
|
<div>
|
|
291
|
-
<h1 class="text-2xl font-semibold">OpenClaw Setup</h1>
|
|
333
|
+
<h1 class="text-2xl font-semibold">OpenClaw Setup${acVersion ? html`${" "}<span class="text-base font-normal text-gray-600">v${acVersion}</span>` : ""}</h1>
|
|
292
334
|
<p class="text-gray-500 text-sm">This should be easy, right?</p>
|
|
293
335
|
</div>
|
|
294
336
|
</div>
|
|
295
337
|
|
|
338
|
+
${acHasUpdate && acLatest && !acDismissed && html`
|
|
339
|
+
<div class="mb-3 flex items-center justify-between gap-3 rounded-lg border border-yellow-500/30 bg-yellow-500/10 px-3 py-2">
|
|
340
|
+
<p class="text-sm text-yellow-400">
|
|
341
|
+
AlphaClaw <span class="font-medium">v${acLatest}</span> is available
|
|
342
|
+
</p>
|
|
343
|
+
<div class="flex items-center gap-2 shrink-0">
|
|
344
|
+
<button
|
|
345
|
+
onclick=${handleAcUpdate}
|
|
346
|
+
disabled=${acUpdating}
|
|
347
|
+
class="text-xs font-medium px-3 py-1 rounded-lg bg-yellow-500/20 text-yellow-300 hover:bg-yellow-500/30 transition-colors ${acUpdating ? "opacity-50 cursor-not-allowed" : ""}"
|
|
348
|
+
>
|
|
349
|
+
${acUpdating ? "Updating..." : "Update now"}
|
|
350
|
+
</button>
|
|
351
|
+
<button
|
|
352
|
+
onclick=${() => setAcDismissed(true)}
|
|
353
|
+
class="text-yellow-500/60 hover:text-yellow-400 transition-colors"
|
|
354
|
+
title="Dismiss"
|
|
355
|
+
>
|
|
356
|
+
<svg class="w-4 h-4" viewBox="0 0 20 20" fill="currentColor">
|
|
357
|
+
<path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"/>
|
|
358
|
+
</svg>
|
|
359
|
+
</button>
|
|
360
|
+
</div>
|
|
361
|
+
</div>
|
|
362
|
+
`}
|
|
363
|
+
|
|
296
364
|
<div class="flex gap-1 border-b border-border">
|
|
297
365
|
${["general", "models", "envars"].map(
|
|
298
366
|
(t) => html`
|
|
@@ -15,15 +15,78 @@ const kGroupLabels = {
|
|
|
15
15
|
const kGroupOrder = ["github", "channels", "tools", "custom"];
|
|
16
16
|
|
|
17
17
|
const kHintByKey = {
|
|
18
|
-
ANTHROPIC_API_KEY: html`From
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
ANTHROPIC_API_KEY: html`From{" "}
|
|
19
|
+
<a
|
|
20
|
+
href="https://console.anthropic.com"
|
|
21
|
+
target="_blank"
|
|
22
|
+
class="text-blue-400 hover:underline"
|
|
23
|
+
>console.anthropic.com</a
|
|
24
|
+
>`,
|
|
25
|
+
ANTHROPIC_TOKEN: html`From{" "}
|
|
26
|
+
<code class="text-xs bg-black/30 px-1 rounded">claude setup-token</code>`,
|
|
27
|
+
OPENAI_API_KEY: html`From{" "}
|
|
28
|
+
<a
|
|
29
|
+
href="https://platform.openai.com"
|
|
30
|
+
target="_blank"
|
|
31
|
+
class="text-blue-400 hover:underline"
|
|
32
|
+
>platform.openai.com</a
|
|
33
|
+
>`,
|
|
34
|
+
GEMINI_API_KEY: html`From{" "}
|
|
35
|
+
<a
|
|
36
|
+
href="https://aistudio.google.com"
|
|
37
|
+
target="_blank"
|
|
38
|
+
class="text-blue-400 hover:underline"
|
|
39
|
+
>aistudio.google.com</a
|
|
40
|
+
>`,
|
|
41
|
+
GITHUB_TOKEN: html`Use a <strong>classic PAT</strong> with{" "}
|
|
42
|
+
<code class="text-xs bg-black/30 px-1 rounded">repo</code> scope from
|
|
43
|
+
<a
|
|
44
|
+
href="https://github.com/settings/tokens"
|
|
45
|
+
target="_blank"
|
|
46
|
+
class="text-blue-400 hover:underline"
|
|
47
|
+
>github.com/settings/tokens</a
|
|
48
|
+
>.`,
|
|
49
|
+
GITHUB_WORKSPACE_REPO: html`Use{" "}
|
|
50
|
+
<code class="text-xs bg-black/30 px-1 rounded">owner/repo</code> or
|
|
51
|
+
<code class="text-xs bg-black/30 px-1 rounded"
|
|
52
|
+
>https://github.com/owner/repo</code
|
|
53
|
+
>`,
|
|
54
|
+
TELEGRAM_BOT_TOKEN: html`From{" "}
|
|
55
|
+
<a
|
|
56
|
+
href="https://t.me/BotFather"
|
|
57
|
+
target="_blank"
|
|
58
|
+
class="text-blue-400 hover:underline"
|
|
59
|
+
>@BotFather</a
|
|
60
|
+
>
|
|
61
|
+
·
|
|
62
|
+
<a
|
|
63
|
+
href="https://docs.openclaw.ai/channels/telegram"
|
|
64
|
+
target="_blank"
|
|
65
|
+
class="text-blue-400 hover:underline"
|
|
66
|
+
>full guide</a
|
|
67
|
+
>`,
|
|
68
|
+
DISCORD_BOT_TOKEN: html`From{" "}
|
|
69
|
+
<a
|
|
70
|
+
href="https://discord.com/developers/applications"
|
|
71
|
+
target="_blank"
|
|
72
|
+
class="text-blue-400 hover:underline"
|
|
73
|
+
>Developer Portal</a
|
|
74
|
+
>
|
|
75
|
+
·
|
|
76
|
+
<a
|
|
77
|
+
href="https://docs.openclaw.ai/channels/discord"
|
|
78
|
+
target="_blank"
|
|
79
|
+
class="text-blue-400 hover:underline"
|
|
80
|
+
>full guide</a
|
|
81
|
+
>`,
|
|
82
|
+
BRAVE_API_KEY: html`From{" "}
|
|
83
|
+
<a
|
|
84
|
+
href="https://brave.com/search/api/"
|
|
85
|
+
target="_blank"
|
|
86
|
+
class="text-blue-400 hover:underline"
|
|
87
|
+
>brave.com/search/api</a
|
|
88
|
+
>
|
|
89
|
+
— free tier available`,
|
|
27
90
|
};
|
|
28
91
|
|
|
29
92
|
const getHintContent = (envVar) => kHintByKey[envVar.key] || envVar.hint || "";
|
|
@@ -74,7 +137,9 @@ const EnvRow = ({ envVar, onChange, onDelete, disabled }) => {
|
|
|
74
137
|
: null}
|
|
75
138
|
</div>
|
|
76
139
|
${getHintContent(envVar)
|
|
77
|
-
? html`<p class="text-xs text-gray-600 mt-1"
|
|
140
|
+
? html`<p class="text-xs text-gray-600 mt-1">
|
|
141
|
+
${getHintContent(envVar)}
|
|
142
|
+
</p>`
|
|
78
143
|
: null}
|
|
79
144
|
</div>
|
|
80
145
|
</div>
|
|
@@ -118,7 +183,9 @@ export const Envars = () => {
|
|
|
118
183
|
if (saving) return;
|
|
119
184
|
setSaving(true);
|
|
120
185
|
try {
|
|
121
|
-
const toSave = vars
|
|
186
|
+
const toSave = vars
|
|
187
|
+
.filter((v) => v.editable)
|
|
188
|
+
.map((v) => ({ key: v.key, value: v.value }));
|
|
122
189
|
const result = await saveEnvVars(toSave);
|
|
123
190
|
const needsRestart = !!result?.restartRequired;
|
|
124
191
|
setRestartRequired(needsRestart);
|
|
@@ -153,11 +220,19 @@ export const Envars = () => {
|
|
|
153
220
|
const [newVal, setNewVal] = useState("");
|
|
154
221
|
|
|
155
222
|
const parsePaste = (input) => {
|
|
156
|
-
const lines = input
|
|
223
|
+
const lines = input
|
|
224
|
+
.split("\n")
|
|
225
|
+
.map((l) => l.trim())
|
|
226
|
+
.filter(Boolean)
|
|
227
|
+
.filter((l) => !l.startsWith("#"));
|
|
157
228
|
const pairs = [];
|
|
158
229
|
for (const line of lines) {
|
|
159
230
|
const eqIdx = line.indexOf("=");
|
|
160
|
-
if (eqIdx > 0)
|
|
231
|
+
if (eqIdx > 0)
|
|
232
|
+
pairs.push({
|
|
233
|
+
key: line.slice(0, eqIdx).trim(),
|
|
234
|
+
value: line.slice(eqIdx + 1).trim(),
|
|
235
|
+
});
|
|
161
236
|
}
|
|
162
237
|
return pairs;
|
|
163
238
|
};
|
|
@@ -173,7 +248,15 @@ export const Envars = () => {
|
|
|
173
248
|
if (existing) {
|
|
174
249
|
existing.value = value;
|
|
175
250
|
} else {
|
|
176
|
-
next.push({
|
|
251
|
+
next.push({
|
|
252
|
+
key,
|
|
253
|
+
value,
|
|
254
|
+
label: key,
|
|
255
|
+
group: "custom",
|
|
256
|
+
hint: "",
|
|
257
|
+
source: "env_file",
|
|
258
|
+
editable: true,
|
|
259
|
+
});
|
|
177
260
|
}
|
|
178
261
|
added++;
|
|
179
262
|
}
|
|
@@ -223,7 +306,10 @@ export const Envars = () => {
|
|
|
223
306
|
};
|
|
224
307
|
|
|
225
308
|
const handleAddVar = () => {
|
|
226
|
-
const key = newKey
|
|
309
|
+
const key = newKey
|
|
310
|
+
.trim()
|
|
311
|
+
.toUpperCase()
|
|
312
|
+
.replace(/[^A-Z0-9_]/g, "_");
|
|
227
313
|
if (!key) return;
|
|
228
314
|
addVars([{ key, value: newVal }]);
|
|
229
315
|
setNewKey("");
|
|
@@ -257,16 +343,18 @@ export const Envars = () => {
|
|
|
257
343
|
onChange=${handleChange}
|
|
258
344
|
onDelete=${handleDelete}
|
|
259
345
|
disabled=${saving}
|
|
260
|
-
|
|
346
|
+
/>`,
|
|
261
347
|
)}
|
|
262
348
|
</div>
|
|
263
|
-
|
|
349
|
+
`,
|
|
264
350
|
)}
|
|
265
351
|
|
|
266
352
|
<div class="bg-surface border border-border rounded-xl p-4 space-y-3">
|
|
267
353
|
<div class="flex items-center justify-between">
|
|
268
354
|
<h3 class="text-sm font-medium text-gray-400">Add Variable</h3>
|
|
269
|
-
<span class="text-xs text-gray-600"
|
|
355
|
+
<span class="text-xs text-gray-600"
|
|
356
|
+
>Paste KEY=VALUE or multiple lines</span
|
|
357
|
+
>
|
|
270
358
|
</div>
|
|
271
359
|
<input
|
|
272
360
|
type="text"
|
|
@@ -326,11 +414,7 @@ export const Envars = () => {
|
|
|
326
414
|
>
|
|
327
415
|
${saving
|
|
328
416
|
? html`<span class="flex items-center justify-center gap-2">
|
|
329
|
-
<svg
|
|
330
|
-
class="animate-spin h-4 w-4"
|
|
331
|
-
viewBox="0 0 24 24"
|
|
332
|
-
fill="none"
|
|
333
|
-
>
|
|
417
|
+
<svg class="animate-spin h-4 w-4" viewBox="0 0 24 24" fill="none">
|
|
334
418
|
<circle
|
|
335
419
|
class="opacity-25"
|
|
336
420
|
cx="12"
|
|
@@ -3,10 +3,8 @@ import { useEffect, useState } from "https://esm.sh/preact/hooks";
|
|
|
3
3
|
import htm from "https://esm.sh/htm";
|
|
4
4
|
import {
|
|
5
5
|
fetchOpenclawVersion,
|
|
6
|
-
fetchAlphaclawVersion,
|
|
7
6
|
restartGateway,
|
|
8
7
|
updateOpenclaw,
|
|
9
|
-
updateAlphaclaw,
|
|
10
8
|
} from "../lib/api.js";
|
|
11
9
|
import { showToast } from "./toast.js";
|
|
12
10
|
const html = htm.bind(h);
|
|
@@ -82,7 +80,7 @@ function VersionRow({ label, currentVersion, fetchVersion, applyUpdate, tagsUrl
|
|
|
82
80
|
<div class="flex items-center justify-between gap-3">
|
|
83
81
|
<div class="min-w-0">
|
|
84
82
|
<p class="text-sm text-gray-300 truncate">
|
|
85
|
-
<span class="text-gray-500">${label}</span>${" "}v${version
|
|
83
|
+
<span class="text-gray-500">${label}</span>${" "}${version ? `v${version}` : "..."}
|
|
86
84
|
</p>
|
|
87
85
|
${error && html`<p class="text-xs text-yellow-500 mt-1">${error}</p>`}
|
|
88
86
|
</div>
|
|
@@ -147,7 +145,7 @@ export function Gateway({ status, openclawVersion }) {
|
|
|
147
145
|
Restart
|
|
148
146
|
</button>
|
|
149
147
|
</div>
|
|
150
|
-
<div class="mt-3 pt-3 border-t border-border
|
|
148
|
+
<div class="mt-3 pt-3 border-t border-border">
|
|
151
149
|
<${VersionRow}
|
|
152
150
|
label="OpenClaw"
|
|
153
151
|
currentVersion=${openclawVersion}
|
|
@@ -155,13 +153,6 @@ export function Gateway({ status, openclawVersion }) {
|
|
|
155
153
|
applyUpdate=${updateOpenclaw}
|
|
156
154
|
tagsUrl="https://github.com/openclaw/openclaw/tags"
|
|
157
155
|
/>
|
|
158
|
-
<${VersionRow}
|
|
159
|
-
label="AlphaClaw"
|
|
160
|
-
currentVersion=${null}
|
|
161
|
-
fetchVersion=${fetchAlphaclawVersion}
|
|
162
|
-
applyUpdate=${updateAlphaclaw}
|
|
163
|
-
tagsUrl="https://www.npmjs.com/package/@chrysb/alphaclaw"
|
|
164
|
-
/>
|
|
165
156
|
</div>
|
|
166
157
|
</div>`;
|
|
167
158
|
}
|
|
@@ -76,9 +76,6 @@ const createOnboardingService = ({
|
|
|
76
76
|
hasCodexOauth,
|
|
77
77
|
workspaceDir: WORKSPACE_DIR,
|
|
78
78
|
});
|
|
79
|
-
console.log(
|
|
80
|
-
`[onboard] Running: openclaw onboard ${onboardArgs.join(" ").replace(/sk-[^\s]+/g, "***")}`,
|
|
81
|
-
);
|
|
82
79
|
await shellCmd(`openclaw onboard ${onboardArgs.map((a) => `"${a}"`).join(" ")}`, {
|
|
83
80
|
env: {
|
|
84
81
|
...process.env,
|