@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 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
- // 7. Install/reconcile system cron entry
521
+ // 9. Install/reconcile system cron entry
520
522
  // ---------------------------------------------------------------------------
521
523
 
522
524
  const packagedHourlyGitSyncPath = path.join(setupDir, "hourly-git-sync.sh");
@@ -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;
@@ -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 { Router, Route, Switch, useLocation } from "https://esm.sh/wouter-preact";
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 { getHashRouterPath, useHashLocation } from "./hooks/use-hash-location.js";
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 = "doctorWarningDismissedUntilMs";
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] = useState(() => {
37
- const settings = readUiSettings();
38
- return Number(settings[kDoctorWarningDismissedUntilUiSettingKey] || 0);
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 } = useAppShellController({
42
- location,
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] = doctorWarningDismissedUntilMs;
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 justify-center pt-12 pb-8 px-4"
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} onComplete=${controllerActions.handleOnboardingComplete} />
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, { view: "edit" }),
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 class=${`mobile-topbar ${shellState.mobileTopbarScrolled ? "is-scrolled" : ""}`}>
189
+ <div
190
+ class=${`mobile-topbar ${shellState.mobileTopbarScrolled ? "is-scrolled" : ""}`}
191
+ >
167
192
  <button
168
193
  class="mobile-topbar-menu"
169
- onclick=${() => shellActions.setMobileSidebarOpen((open) => !open)}
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 width="18" height="18" viewBox="0 0 16 16" fill="currentColor">
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(Date.now() + kOneWeekMs)}
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(params.sessionId || "")}
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)">v${controllerState.acVersion}</span>`
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 0;
34
- const clampedStep = Math.max(0, Math.min(kPairingStepIndex, parsedStep));
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
  });
@@ -29,7 +29,7 @@ export const kWelcomeGroups = [
29
29
  {
30
30
  id: "github",
31
31
  title: "GitHub",
32
- description: "Backs up your agent's config and workspace",
32
+ description: "Auto-backup your config and workspace",
33
33
  fields: [
34
34
  {
35
35
  key: "_GITHUB_SOURCE_REPO",
@@ -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 > 0
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 > 0
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
- <div class="mt-4 mb-2 flex items-center justify-center">
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
- Step ${stepNumber} of ${progressSteps.length} - ${activeStepLabel}
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 = idx < step || (isSetupStep && group.id === "setup");
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 = isActive
50
- ? "rgba(99, 235, 255, 0.9)"
51
- : group.id === "pairing"
52
- ? isPairingComplete
53
- ? "rgba(99, 235, 255, 0.55)"
54
- : "rgba(82, 94, 122, 0.45)"
55
- : isComplete
56
- ? "rgba(99, 235, 255, 0.55)"
57
- : "rgba(82, 94, 122, 0.45)";
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.isImportStep
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(0, prev - 1));
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 = isImportStep
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
- isImportStep || isSecretReviewStep || isPlaceholderReviewStep
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 = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chrysb/alphaclaw",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },