@chrysb/alphaclaw 0.5.0 → 0.5.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/bin/alphaclaw.js +3 -1
- package/lib/public/css/theme.css +57 -0
- package/lib/public/js/app.js +63 -26
- package/lib/public/js/components/onboarding/use-welcome-storage.js +2 -2
- package/lib/public/js/components/onboarding/welcome-config.js +1 -1
- package/lib/public/js/components/onboarding/welcome-form-step.js +2 -23
- package/lib/public/js/components/onboarding/welcome-header.js +19 -13
- package/lib/public/js/components/onboarding/welcome-pre-step.js +81 -0
- package/lib/public/js/components/welcome/index.js +13 -2
- package/lib/public/js/components/welcome/use-welcome.js +16 -4
- package/lib/server/onboarding/workspace.js +10 -0
- package/package.json +1 -1
package/bin/alphaclaw.js
CHANGED
|
@@ -481,6 +481,8 @@ if (!kSetupPassword) {
|
|
|
481
481
|
|
|
482
482
|
process.env.OPENCLAW_HOME = rootDir;
|
|
483
483
|
process.env.OPENCLAW_CONFIG_PATH = path.join(openclawDir, "openclaw.json");
|
|
484
|
+
process.env.GOG_KEYRING_PASSWORD =
|
|
485
|
+
process.env.GOG_KEYRING_PASSWORD || "alphaclaw";
|
|
484
486
|
|
|
485
487
|
// ---------------------------------------------------------------------------
|
|
486
488
|
// 8. Install gog (Google Workspace CLI) if not present
|
|
@@ -516,7 +518,7 @@ if (!gogInstalled) {
|
|
|
516
518
|
}
|
|
517
519
|
|
|
518
520
|
// ---------------------------------------------------------------------------
|
|
519
|
-
//
|
|
521
|
+
// 9. Install/reconcile system cron entry
|
|
520
522
|
// ---------------------------------------------------------------------------
|
|
521
523
|
|
|
522
524
|
const packagedHourlyGitSyncPath = path.join(setupDir, "hourly-git-sync.sh");
|
package/lib/public/css/theme.css
CHANGED
|
@@ -246,6 +246,45 @@ textarea:focus {
|
|
|
246
246
|
background: rgba(99, 235, 255, 0.08);
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
+
.ac-path-card {
|
|
250
|
+
border: 1px solid var(--panel-border-contrast);
|
|
251
|
+
background: rgba(0, 0, 0, 0.2);
|
|
252
|
+
transition:
|
|
253
|
+
border-color 0.15s ease,
|
|
254
|
+
background 0.15s ease,
|
|
255
|
+
box-shadow 0.15s ease,
|
|
256
|
+
transform 0.15s ease;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.ac-path-card:hover {
|
|
260
|
+
border-color: rgba(99, 235, 255, 0.5);
|
|
261
|
+
background: rgba(99, 235, 255, 0.04);
|
|
262
|
+
box-shadow:
|
|
263
|
+
inset 0 0 0 1px rgba(99, 235, 255, 0.1),
|
|
264
|
+
0 0 12px rgba(99, 235, 255, 0.08);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.ac-path-card:hover .ac-path-icon {
|
|
268
|
+
color: var(--accent);
|
|
269
|
+
border-color: rgba(99, 235, 255, 0.3);
|
|
270
|
+
background: rgba(99, 235, 255, 0.1);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.ac-path-card:hover .ac-path-title {
|
|
274
|
+
color: #b9f8ff;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.ac-path-card:hover .ac-path-desc {
|
|
278
|
+
color: #94a3b8;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.ac-path-icon {
|
|
282
|
+
transition:
|
|
283
|
+
color 0.15s ease,
|
|
284
|
+
border-color 0.15s ease,
|
|
285
|
+
background 0.15s ease;
|
|
286
|
+
}
|
|
287
|
+
|
|
249
288
|
.ac-btn-secondary {
|
|
250
289
|
border: 1px solid var(--panel-border-contrast);
|
|
251
290
|
color: #d1d5db;
|
|
@@ -426,6 +465,24 @@ textarea:focus {
|
|
|
426
465
|
}
|
|
427
466
|
}
|
|
428
467
|
|
|
468
|
+
@keyframes acStepPillPulse {
|
|
469
|
+
0%,
|
|
470
|
+
100% {
|
|
471
|
+
box-shadow:
|
|
472
|
+
0 0 0 0 rgba(99, 235, 255, 0.14),
|
|
473
|
+
0 0 5px rgba(99, 235, 255, 0.18);
|
|
474
|
+
}
|
|
475
|
+
50% {
|
|
476
|
+
box-shadow:
|
|
477
|
+
0 0 0 3px rgba(99, 235, 255, 0.08),
|
|
478
|
+
0 0 9px rgba(99, 235, 255, 0.32);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.ac-step-pill-pulse {
|
|
483
|
+
animation: acStepPillPulse 2.6s ease-in-out infinite;
|
|
484
|
+
}
|
|
485
|
+
|
|
429
486
|
.ac-status-dot {
|
|
430
487
|
width: 8px;
|
|
431
488
|
height: 8px;
|
package/lib/public/js/app.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { h, render } from "https://esm.sh/preact";
|
|
2
2
|
import { useState, useEffect } from "https://esm.sh/preact/hooks";
|
|
3
3
|
import htm from "https://esm.sh/htm";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Router,
|
|
6
|
+
Route,
|
|
7
|
+
Switch,
|
|
8
|
+
useLocation,
|
|
9
|
+
} from "https://esm.sh/wouter-preact";
|
|
5
10
|
import { logout } from "./lib/api.js";
|
|
6
11
|
import { Welcome } from "./components/welcome/index.js";
|
|
7
12
|
import { ToastContainer } from "./components/toast.js";
|
|
@@ -14,7 +19,6 @@ import {
|
|
|
14
19
|
EnvarsRoute,
|
|
15
20
|
GeneralRoute,
|
|
16
21
|
ModelsRoute,
|
|
17
|
-
ProvidersRoute,
|
|
18
22
|
RouteRedirect,
|
|
19
23
|
TelegramRoute,
|
|
20
24
|
UsageRoute,
|
|
@@ -24,34 +28,48 @@ import {
|
|
|
24
28
|
import { useAppShellController } from "./hooks/use-app-shell-controller.js";
|
|
25
29
|
import { useAppShellUi } from "./hooks/use-app-shell-ui.js";
|
|
26
30
|
import { useBrowseNavigation } from "./hooks/use-browse-navigation.js";
|
|
27
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
getHashRouterPath,
|
|
33
|
+
useHashLocation,
|
|
34
|
+
} from "./hooks/use-hash-location.js";
|
|
28
35
|
import { readUiSettings, writeUiSettings } from "./lib/ui-settings.js";
|
|
29
36
|
|
|
30
37
|
const html = htm.bind(h);
|
|
31
|
-
const kDoctorWarningDismissedUntilUiSettingKey =
|
|
38
|
+
const kDoctorWarningDismissedUntilUiSettingKey =
|
|
39
|
+
"doctorWarningDismissedUntilMs";
|
|
32
40
|
const kOneWeekMs = 7 * 24 * 60 * 60 * 1000;
|
|
33
41
|
|
|
34
42
|
const App = () => {
|
|
35
43
|
const [location, setLocation] = useLocation();
|
|
36
|
-
const [doctorWarningDismissedUntilMs, setDoctorWarningDismissedUntilMs] =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
const [doctorWarningDismissedUntilMs, setDoctorWarningDismissedUntilMs] =
|
|
45
|
+
useState(() => {
|
|
46
|
+
const settings = readUiSettings();
|
|
47
|
+
return Number(settings[kDoctorWarningDismissedUntilUiSettingKey] || 0);
|
|
48
|
+
});
|
|
40
49
|
|
|
41
|
-
const { state: controllerState, actions: controllerActions } =
|
|
42
|
-
|
|
43
|
-
});
|
|
44
|
-
const { refs: shellRefs, state: shellState, actions: shellActions } = useAppShellUi();
|
|
45
|
-
const { state: browseState, actions: browseActions, constants: browseConstants } =
|
|
46
|
-
useBrowseNavigation({
|
|
50
|
+
const { state: controllerState, actions: controllerActions } =
|
|
51
|
+
useAppShellController({
|
|
47
52
|
location,
|
|
48
|
-
setLocation,
|
|
49
|
-
onCloseMobileSidebar: shellActions.closeMobileSidebar,
|
|
50
53
|
});
|
|
54
|
+
const {
|
|
55
|
+
refs: shellRefs,
|
|
56
|
+
state: shellState,
|
|
57
|
+
actions: shellActions,
|
|
58
|
+
} = useAppShellUi();
|
|
59
|
+
const {
|
|
60
|
+
state: browseState,
|
|
61
|
+
actions: browseActions,
|
|
62
|
+
constants: browseConstants,
|
|
63
|
+
} = useBrowseNavigation({
|
|
64
|
+
location,
|
|
65
|
+
setLocation,
|
|
66
|
+
onCloseMobileSidebar: shellActions.closeMobileSidebar,
|
|
67
|
+
});
|
|
51
68
|
|
|
52
69
|
useEffect(() => {
|
|
53
70
|
const settings = readUiSettings();
|
|
54
|
-
settings[kDoctorWarningDismissedUntilUiSettingKey] =
|
|
71
|
+
settings[kDoctorWarningDismissedUntilUiSettingKey] =
|
|
72
|
+
doctorWarningDismissedUntilMs;
|
|
55
73
|
writeUiSettings(settings);
|
|
56
74
|
}, [doctorWarningDismissedUntilMs]);
|
|
57
75
|
|
|
@@ -83,10 +101,13 @@ const App = () => {
|
|
|
83
101
|
if (!controllerState.onboarded) {
|
|
84
102
|
return html`
|
|
85
103
|
<div
|
|
86
|
-
class="min-h-screen flex
|
|
104
|
+
class="min-h-screen flex flex-col items-center pt-12 pb-8 px-4"
|
|
87
105
|
style="position: relative; z-index: 1"
|
|
88
106
|
>
|
|
89
|
-
<${Welcome}
|
|
107
|
+
<${Welcome}
|
|
108
|
+
onComplete=${controllerActions.handleOnboardingComplete}
|
|
109
|
+
acVersion=${controllerState.acVersion}
|
|
110
|
+
/>
|
|
90
111
|
</div>
|
|
91
112
|
<${ToastContainer} />
|
|
92
113
|
`;
|
|
@@ -150,7 +171,9 @@ const App = () => {
|
|
|
150
171
|
onNavigateToBrowseFile=${browseActions.navigateToBrowseFile}
|
|
151
172
|
onEditSelectedBrowseFile=${() =>
|
|
152
173
|
setLocation(
|
|
153
|
-
browseActions.buildBrowseRoute(browseState.selectedBrowsePath, {
|
|
174
|
+
browseActions.buildBrowseRoute(browseState.selectedBrowsePath, {
|
|
175
|
+
view: "edit",
|
|
176
|
+
}),
|
|
154
177
|
)}
|
|
155
178
|
onClearSelection=${() => {
|
|
156
179
|
browseActions.clearBrowsePreview();
|
|
@@ -163,14 +186,22 @@ const App = () => {
|
|
|
163
186
|
onscroll=${shellActions.handlePaneScroll}
|
|
164
187
|
style=${{ display: browseState.isBrowseRoute ? "none" : "block" }}
|
|
165
188
|
>
|
|
166
|
-
<div
|
|
189
|
+
<div
|
|
190
|
+
class=${`mobile-topbar ${shellState.mobileTopbarScrolled ? "is-scrolled" : ""}`}
|
|
191
|
+
>
|
|
167
192
|
<button
|
|
168
193
|
class="mobile-topbar-menu"
|
|
169
|
-
onclick=${() =>
|
|
194
|
+
onclick=${() =>
|
|
195
|
+
shellActions.setMobileSidebarOpen((open) => !open)}
|
|
170
196
|
aria-label="Open menu"
|
|
171
197
|
aria-expanded=${shellState.mobileSidebarOpen ? "true" : "false"}
|
|
172
198
|
>
|
|
173
|
-
<svg
|
|
199
|
+
<svg
|
|
200
|
+
width="18"
|
|
201
|
+
height="18"
|
|
202
|
+
viewBox="0 0 16 16"
|
|
203
|
+
fill="currentColor"
|
|
204
|
+
>
|
|
174
205
|
<path
|
|
175
206
|
d="M2 3.75a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 3.75zm0 4.25a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 8zm0 4.25a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75a.75.75 0 01-.75-.75z"
|
|
176
207
|
/>
|
|
@@ -201,7 +232,9 @@ const App = () => {
|
|
|
201
232
|
onOpenclawUpdate=${controllerActions.handleOpenclawUpdate}
|
|
202
233
|
onRestartRequired=${controllerActions.setRestartRequired}
|
|
203
234
|
onDismissDoctorWarning=${() =>
|
|
204
|
-
setDoctorWarningDismissedUntilMs(
|
|
235
|
+
setDoctorWarningDismissedUntilMs(
|
|
236
|
+
Date.now() + kOneWeekMs,
|
|
237
|
+
)}
|
|
205
238
|
/>
|
|
206
239
|
</${Route}>
|
|
207
240
|
<${Route} path="/doctor">
|
|
@@ -232,7 +265,9 @@ const App = () => {
|
|
|
232
265
|
<${Route} path="/usage/:sessionId">
|
|
233
266
|
${(params) => html`
|
|
234
267
|
<${UsageRoute}
|
|
235
|
-
sessionId=${decodeURIComponent(
|
|
268
|
+
sessionId=${decodeURIComponent(
|
|
269
|
+
params.sessionId || "",
|
|
270
|
+
)}
|
|
236
271
|
onSetLocation=${setLocation}
|
|
237
272
|
/>
|
|
238
273
|
`}
|
|
@@ -280,7 +315,9 @@ const App = () => {
|
|
|
280
315
|
<div class="app-statusbar">
|
|
281
316
|
<div class="statusbar-left">
|
|
282
317
|
${controllerState.acVersion
|
|
283
|
-
? html`<span style="color: var(--text-muted)"
|
|
318
|
+
? html`<span style="color: var(--text-muted)"
|
|
319
|
+
>v${controllerState.acVersion}</span
|
|
320
|
+
>`
|
|
284
321
|
: null}
|
|
285
322
|
</div>
|
|
286
323
|
<div class="statusbar-right">
|
|
@@ -30,8 +30,8 @@ export const useWelcomeStorage = ({
|
|
|
30
30
|
String(initialSetupState?.[kOnboardingStepKey] || ""),
|
|
31
31
|
10,
|
|
32
32
|
);
|
|
33
|
-
if (!Number.isFinite(parsedStep)) return
|
|
34
|
-
const clampedStep = Math.max(
|
|
33
|
+
if (!Number.isFinite(parsedStep)) return -1;
|
|
34
|
+
const clampedStep = Math.max(-1, Math.min(kPairingStepIndex, parsedStep));
|
|
35
35
|
if (clampedStep === kSetupStepIndex && shouldRecoverFromSetupState) return 0;
|
|
36
36
|
return clampedStep;
|
|
37
37
|
});
|
|
@@ -6,7 +6,6 @@ import { ActionButton } from "../action-button.js";
|
|
|
6
6
|
import { Badge } from "../badge.js";
|
|
7
7
|
import { SegmentedControl } from "../segmented-control.js";
|
|
8
8
|
import {
|
|
9
|
-
isValidGithubRepoInput,
|
|
10
9
|
kGithubFlowFresh,
|
|
11
10
|
kGithubFlowImport,
|
|
12
11
|
kGithubTargetRepoModeCreate,
|
|
@@ -195,29 +194,9 @@ export const WelcomeFormStep = ({
|
|
|
195
194
|
${activeGroup.id === "github" &&
|
|
196
195
|
html`
|
|
197
196
|
<div class="space-y-3">
|
|
198
|
-
<div class="space-y-1 pt-1">
|
|
199
|
-
<div>
|
|
200
|
-
<label class="text-xs font-medium text-gray-400">Setup mode</label>
|
|
201
|
-
</div>
|
|
202
|
-
<${SegmentedControl}
|
|
203
|
-
options=${[
|
|
204
|
-
{ label: "Start fresh", value: kGithubFlowFresh },
|
|
205
|
-
{ label: "Import existing setup", value: kGithubFlowImport },
|
|
206
|
-
]}
|
|
207
|
-
value=${githubFlow}
|
|
208
|
-
onChange=${(value) => setValue("_GITHUB_FLOW", value)}
|
|
209
|
-
size="md"
|
|
210
|
-
fullWidth=${true}
|
|
211
|
-
/>
|
|
212
|
-
</div>
|
|
213
197
|
${githubFlow === kGithubFlowFresh
|
|
214
198
|
? html`
|
|
215
199
|
<div class="space-y-1">
|
|
216
|
-
<div>
|
|
217
|
-
<label class="text-xs font-medium text-gray-400"
|
|
218
|
-
>Repository setup</label
|
|
219
|
-
>
|
|
220
|
-
</div>
|
|
221
200
|
<${SegmentedControl}
|
|
222
201
|
options=${[
|
|
223
202
|
{
|
|
@@ -366,7 +345,7 @@ export const WelcomeFormStep = ({
|
|
|
366
345
|
<div class="grid grid-cols-2 gap-2 pt-3">
|
|
367
346
|
${step < totalGroups - 1
|
|
368
347
|
? html`
|
|
369
|
-
${step
|
|
348
|
+
${step >= 0
|
|
370
349
|
? html`<${ActionButton}
|
|
371
350
|
onClick=${goBack}
|
|
372
351
|
tone="secondary"
|
|
@@ -390,7 +369,7 @@ export const WelcomeFormStep = ({
|
|
|
390
369
|
/>
|
|
391
370
|
`
|
|
392
371
|
: html`
|
|
393
|
-
${step
|
|
372
|
+
${step >= 0
|
|
394
373
|
? html`<${ActionButton}
|
|
395
374
|
onClick=${goBack}
|
|
396
375
|
tone="secondary"
|
|
@@ -6,6 +6,7 @@ const html = htm.bind(h);
|
|
|
6
6
|
export const WelcomeHeader = ({
|
|
7
7
|
groups,
|
|
8
8
|
step,
|
|
9
|
+
isPreStep,
|
|
9
10
|
isSetupStep,
|
|
10
11
|
isPairingStep,
|
|
11
12
|
stepNumber,
|
|
@@ -30,12 +31,14 @@ export const WelcomeHeader = ({
|
|
|
30
31
|
<p style="color: var(--text-muted)" class="text-sm">
|
|
31
32
|
Let's get your agent running
|
|
32
33
|
</p>
|
|
33
|
-
|
|
34
|
+
<div class="mt-4 mb-2 flex items-center justify-center">
|
|
34
35
|
<span
|
|
35
36
|
class="text-[11px] px-2.5 py-1 rounded-full border border-border font-medium"
|
|
36
37
|
style="background: rgba(0, 0, 0, 0.3); color: var(--text-muted)"
|
|
37
38
|
>
|
|
38
|
-
|
|
39
|
+
${isPreStep
|
|
40
|
+
? "Choose your destiny"
|
|
41
|
+
: `Step ${stepNumber} of ${progressSteps.length} - ${activeStepLabel}`}
|
|
39
42
|
</span>
|
|
40
43
|
</div>
|
|
41
44
|
</div>
|
|
@@ -43,21 +46,24 @@ export const WelcomeHeader = ({
|
|
|
43
46
|
<div class="flex items-center gap-2">
|
|
44
47
|
${progressSteps.map((group, idx) => {
|
|
45
48
|
const isActive = idx === step;
|
|
46
|
-
const isComplete =
|
|
49
|
+
const isComplete =
|
|
50
|
+
idx < step || (isSetupStep && group.id === "setup");
|
|
47
51
|
const isPairingComplete =
|
|
48
52
|
idx < step || (isPairingStep && group.id === "pairing");
|
|
49
|
-
const bg =
|
|
50
|
-
? "rgba(
|
|
51
|
-
:
|
|
52
|
-
?
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
:
|
|
53
|
+
const bg = isPreStep
|
|
54
|
+
? "rgba(82, 94, 122, 0.45)"
|
|
55
|
+
: isActive
|
|
56
|
+
? "rgba(99, 235, 255, 0.9)"
|
|
57
|
+
: group.id === "pairing"
|
|
58
|
+
? isPairingComplete
|
|
59
|
+
? "rgba(99, 235, 255, 0.55)"
|
|
60
|
+
: "rgba(82, 94, 122, 0.45)"
|
|
61
|
+
: isComplete
|
|
62
|
+
? "rgba(99, 235, 255, 0.55)"
|
|
63
|
+
: "rgba(82, 94, 122, 0.45)";
|
|
58
64
|
return html`
|
|
59
65
|
<div
|
|
60
|
-
class="h-1 flex-1 rounded-full transition-colors"
|
|
66
|
+
class="h-1 flex-1 rounded-full transition-colors ${isActive ? "ac-step-pill-pulse" : ""}"
|
|
61
67
|
style=${{ background: bg }}
|
|
62
68
|
title=${group.title}
|
|
63
69
|
></div>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { h } from "https://esm.sh/preact";
|
|
2
|
+
import htm from "https://esm.sh/htm";
|
|
3
|
+
import { kGithubFlowFresh, kGithubFlowImport } from "./welcome-config.js";
|
|
4
|
+
|
|
5
|
+
const html = htm.bind(h);
|
|
6
|
+
|
|
7
|
+
export const WelcomePreStep = ({ onSelectFlow }) => {
|
|
8
|
+
return html`
|
|
9
|
+
<div class="space-y-3">
|
|
10
|
+
<button
|
|
11
|
+
type="button"
|
|
12
|
+
onclick=${() => onSelectFlow(kGithubFlowFresh)}
|
|
13
|
+
class="w-full flex items-center gap-4 text-left p-4 rounded-xl ac-path-card"
|
|
14
|
+
>
|
|
15
|
+
<div
|
|
16
|
+
class="ac-path-icon flex-shrink-0 w-10 h-10 flex items-center justify-center bg-black/30 rounded-lg border border-border text-gray-300"
|
|
17
|
+
>
|
|
18
|
+
<svg
|
|
19
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
20
|
+
viewBox="0 0 24 24"
|
|
21
|
+
fill="currentColor"
|
|
22
|
+
class="w-5 h-5"
|
|
23
|
+
>
|
|
24
|
+
<path
|
|
25
|
+
d="M14 4.4375C15.3462 4.4375 16.4375 3.34619 16.4375 2H17.5625C17.5625 3.34619 18.6538 4.4375 20 4.4375V5.5625C18.6538 5.5625 17.5625 6.65381 17.5625 8H16.4375C16.4375 6.65381 15.3462 5.5625 14 5.5625V4.4375ZM1 11C4.31371 11 7 8.31371 7 5H9C9 8.31371 11.6863 11 15 11V13C11.6863 13 9 15.6863 9 19H7C7 15.6863 4.31371 13 1 13V11ZM4.87601 12C6.18717 12.7276 7.27243 13.8128 8 15.124 8.72757 13.8128 9.81283 12.7276 11.124 12 9.81283 11.2724 8.72757 10.1872 8 8.87601 7.27243 10.1872 6.18717 11.2724 4.87601 12ZM17.25 14C17.25 15.7949 15.7949 17.25 14 17.25V18.75C15.7949 18.75 17.25 20.2051 17.25 22H18.75C18.75 20.2051 20.2051 18.75 22 18.75V17.25C20.2051 17.25 18.75 15.7949 18.75 14H17.25Z"
|
|
26
|
+
></path>
|
|
27
|
+
</svg>
|
|
28
|
+
</div>
|
|
29
|
+
<div>
|
|
30
|
+
<div
|
|
31
|
+
class="ac-path-title text-sm font-medium text-gray-200 mb-0.5 transition-colors duration-150"
|
|
32
|
+
>
|
|
33
|
+
Start fresh
|
|
34
|
+
</div>
|
|
35
|
+
<div
|
|
36
|
+
class="ac-path-desc text-xs text-gray-500 transition-colors duration-150"
|
|
37
|
+
>
|
|
38
|
+
Create a new repository and set up your agent from scratch.
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</button>
|
|
42
|
+
|
|
43
|
+
<button
|
|
44
|
+
type="button"
|
|
45
|
+
onclick=${() => onSelectFlow(kGithubFlowImport)}
|
|
46
|
+
class="w-full flex items-center gap-4 text-left p-4 rounded-xl ac-path-card"
|
|
47
|
+
>
|
|
48
|
+
<div
|
|
49
|
+
class="ac-path-icon flex-shrink-0 w-10 h-10 flex items-center justify-center bg-black/30 rounded-lg border border-border text-gray-300"
|
|
50
|
+
>
|
|
51
|
+
<svg
|
|
52
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
53
|
+
viewBox="0 0 24 24"
|
|
54
|
+
fill="none"
|
|
55
|
+
stroke="currentColor"
|
|
56
|
+
stroke-width="2"
|
|
57
|
+
stroke-linecap="round"
|
|
58
|
+
stroke-linejoin="round"
|
|
59
|
+
class="w-5 h-5"
|
|
60
|
+
>
|
|
61
|
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
|
62
|
+
<polyline points="7 10 12 15 17 10"></polyline>
|
|
63
|
+
<line x1="12" y1="15" x2="12" y2="3"></line>
|
|
64
|
+
</svg>
|
|
65
|
+
</div>
|
|
66
|
+
<div>
|
|
67
|
+
<div
|
|
68
|
+
class="ac-path-title text-sm font-medium text-gray-200 mb-0.5 transition-colors duration-150"
|
|
69
|
+
>
|
|
70
|
+
Import existing setup
|
|
71
|
+
</div>
|
|
72
|
+
<div
|
|
73
|
+
class="ac-path-desc text-xs text-gray-500 transition-colors duration-150"
|
|
74
|
+
>
|
|
75
|
+
Connect an existing repository that already has an OpenClaw setup.
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</button>
|
|
79
|
+
</div>
|
|
80
|
+
`;
|
|
81
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { h } from "https://esm.sh/preact";
|
|
2
2
|
import htm from "https://esm.sh/htm";
|
|
3
3
|
import { kWelcomeGroups } from "../onboarding/welcome-config.js";
|
|
4
|
+
import { WelcomePreStep } from "../onboarding/welcome-pre-step.js";
|
|
4
5
|
import { WelcomeImportStep } from "../onboarding/welcome-import-step.js";
|
|
5
6
|
import { WelcomePlaceholderReviewStep } from "../onboarding/welcome-placeholder-review-step.js";
|
|
6
7
|
import { WelcomeSecretReviewStep } from "../onboarding/welcome-secret-review-step.js";
|
|
@@ -12,7 +13,7 @@ import { useWelcome } from "./use-welcome.js";
|
|
|
12
13
|
|
|
13
14
|
const html = htm.bind(h);
|
|
14
15
|
|
|
15
|
-
export const Welcome = ({ onComplete }) => {
|
|
16
|
+
export const Welcome = ({ onComplete, acVersion }) => {
|
|
16
17
|
const { state, actions } = useWelcome({ onComplete });
|
|
17
18
|
|
|
18
19
|
return html`
|
|
@@ -20,6 +21,7 @@ export const Welcome = ({ onComplete }) => {
|
|
|
20
21
|
<${WelcomeHeader}
|
|
21
22
|
groups=${kWelcomeGroups}
|
|
22
23
|
step=${state.step}
|
|
24
|
+
isPreStep=${state.isPreStep}
|
|
23
25
|
isSetupStep=${state.isSetupStep}
|
|
24
26
|
isPairingStep=${state.isPairingStep}
|
|
25
27
|
stepNumber=${state.stepNumber}
|
|
@@ -27,7 +29,9 @@ export const Welcome = ({ onComplete }) => {
|
|
|
27
29
|
/>
|
|
28
30
|
|
|
29
31
|
<div class="bg-surface border border-border rounded-xl p-4 space-y-3">
|
|
30
|
-
${state.
|
|
32
|
+
${state.isPreStep
|
|
33
|
+
? html`<${WelcomePreStep} onSelectFlow=${actions.handleSelectFlow} />`
|
|
34
|
+
: state.isImportStep
|
|
31
35
|
? html`<${WelcomeImportStep}
|
|
32
36
|
scanResult=${state.importScanResult}
|
|
33
37
|
scanning=${state.importScanning}
|
|
@@ -107,6 +111,13 @@ export const Welcome = ({ onComplete }) => {
|
|
|
107
111
|
/>
|
|
108
112
|
`}
|
|
109
113
|
</div>
|
|
114
|
+
${acVersion
|
|
115
|
+
? html`
|
|
116
|
+
<div class="text-center text-xs text-gray-500 font-mono mt-8">
|
|
117
|
+
v${acVersion}
|
|
118
|
+
</div>
|
|
119
|
+
`
|
|
120
|
+
: null}
|
|
110
121
|
</div>
|
|
111
122
|
`;
|
|
112
123
|
};
|
|
@@ -160,9 +160,10 @@ export const useWelcome = ({ onComplete }) => {
|
|
|
160
160
|
: false;
|
|
161
161
|
|
|
162
162
|
const allValid = kWelcomeGroups.every((group) => group.validate(vals, { hasAi }));
|
|
163
|
+
const isPreStep = step === -1;
|
|
163
164
|
const isSetupStep = step === kSetupStepIndex;
|
|
164
165
|
const isPairingStep = step === kPairingStepIndex;
|
|
165
|
-
const activeGroup = step < kSetupStepIndex ? kWelcomeGroups[step] : null;
|
|
166
|
+
const activeGroup = step >= 0 && step < kSetupStepIndex ? kWelcomeGroups[step] : null;
|
|
166
167
|
const currentGroupValid = activeGroup
|
|
167
168
|
? activeGroup.validate(vals, { hasAi })
|
|
168
169
|
: false;
|
|
@@ -277,7 +278,7 @@ export const useWelcome = ({ onComplete }) => {
|
|
|
277
278
|
const goBack = () => {
|
|
278
279
|
if (isSetupStep) return;
|
|
279
280
|
setFormError(null);
|
|
280
|
-
setStep((prev) => Math.max(
|
|
281
|
+
setStep((prev) => Math.max(-1, prev - 1));
|
|
281
282
|
};
|
|
282
283
|
|
|
283
284
|
const goBackFromSetupError = () => {
|
|
@@ -469,10 +470,17 @@ export const useWelcome = ({ onComplete }) => {
|
|
|
469
470
|
setStep((prev) => Math.min(kWelcomeGroups.length - 1, prev + 1));
|
|
470
471
|
};
|
|
471
472
|
|
|
473
|
+
const handleSelectFlow = (flow) => {
|
|
474
|
+
setValue("_GITHUB_FLOW", flow);
|
|
475
|
+
setStep(0);
|
|
476
|
+
};
|
|
477
|
+
|
|
472
478
|
const isImportStep = importStep === kImportStepId;
|
|
473
479
|
const isSecretReviewStep = importStep === kSecretReviewStepId;
|
|
474
480
|
const isPlaceholderReviewStep = importStep === kPlaceholderReviewStepId;
|
|
475
|
-
const activeStepLabel =
|
|
481
|
+
const activeStepLabel = isPreStep
|
|
482
|
+
? "Getting Started"
|
|
483
|
+
: isImportStep
|
|
476
484
|
? "Import"
|
|
477
485
|
: isSecretReviewStep
|
|
478
486
|
? "Review Secrets"
|
|
@@ -484,7 +492,9 @@ export const useWelcome = ({ onComplete }) => {
|
|
|
484
492
|
? "Pairing"
|
|
485
493
|
: activeGroup?.title || "Setup";
|
|
486
494
|
const stepNumber =
|
|
487
|
-
|
|
495
|
+
isPreStep
|
|
496
|
+
? 0
|
|
497
|
+
: isImportStep || isSecretReviewStep || isPlaceholderReviewStep
|
|
488
498
|
? step + 1
|
|
489
499
|
: isSetupStep
|
|
490
500
|
? kWelcomeGroups.length + 1
|
|
@@ -512,6 +522,7 @@ export const useWelcome = ({ onComplete }) => {
|
|
|
512
522
|
visibleAiFieldKeys,
|
|
513
523
|
hasAi,
|
|
514
524
|
allValid,
|
|
525
|
+
isPreStep,
|
|
515
526
|
isSetupStep,
|
|
516
527
|
isPairingStep,
|
|
517
528
|
activeGroup,
|
|
@@ -549,6 +560,7 @@ export const useWelcome = ({ onComplete }) => {
|
|
|
549
560
|
goBack,
|
|
550
561
|
goBackFromSetupError,
|
|
551
562
|
goNext,
|
|
563
|
+
handleSelectFlow,
|
|
552
564
|
handleImportApprove,
|
|
553
565
|
handleShowSecretReview,
|
|
554
566
|
handleSecretReviewBack,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
|
+
const { execSync } = require("child_process");
|
|
2
3
|
const {
|
|
3
4
|
kSetupDir,
|
|
4
5
|
OPENCLAW_DIR,
|
|
@@ -139,6 +140,15 @@ const ensureOpenclawRuntimeArtifacts = ({
|
|
|
139
140
|
} catch (e) {
|
|
140
141
|
console.log(`[alphaclaw] .env symlink skipped: ${e.message}`);
|
|
141
142
|
}
|
|
143
|
+
|
|
144
|
+
const gogConfigFile = path.join(openclawDir, "gogcli", "config.json");
|
|
145
|
+
if (!fs.existsSync(gogConfigFile)) {
|
|
146
|
+
fs.mkdirSync(path.join(openclawDir, "gogcli"), { recursive: true });
|
|
147
|
+
try {
|
|
148
|
+
execSync("gog auth keyring file", { stdio: "ignore" });
|
|
149
|
+
console.log("[alphaclaw] gog keyring configured (file backend)");
|
|
150
|
+
} catch {}
|
|
151
|
+
}
|
|
142
152
|
};
|
|
143
153
|
|
|
144
154
|
module.exports = {
|