@chrysb/alphaclaw 0.4.6-beta.8 → 0.4.6-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/bin/alphaclaw.js +2 -32
  2. package/lib/public/css/theme.css +19 -0
  3. package/lib/public/js/app.js +1 -1
  4. package/lib/public/js/components/envars.js +0 -1
  5. package/lib/public/js/components/onboarding/welcome-config.js +39 -17
  6. package/lib/public/js/components/onboarding/welcome-form-step.js +142 -47
  7. package/lib/public/js/components/onboarding/welcome-import-step.js +306 -0
  8. package/lib/public/js/components/onboarding/welcome-placeholder-review-step.js +99 -0
  9. package/lib/public/js/components/onboarding/welcome-secret-review-step.js +191 -0
  10. package/lib/public/js/components/segmented-control.js +7 -1
  11. package/lib/public/js/components/welcome/index.js +112 -0
  12. package/lib/public/js/components/welcome/use-welcome.js +561 -0
  13. package/lib/public/js/lib/api.js +221 -161
  14. package/lib/server/commands.js +1 -0
  15. package/lib/server/constants.js +0 -1
  16. package/lib/server/gateway.js +15 -40
  17. package/lib/server/onboarding/github.js +120 -19
  18. package/lib/server/onboarding/import/import-applier.js +321 -0
  19. package/lib/server/onboarding/import/import-config.js +69 -0
  20. package/lib/server/onboarding/import/import-scanner.js +469 -0
  21. package/lib/server/onboarding/import/import-temp.js +63 -0
  22. package/lib/server/onboarding/import/secret-detector.js +289 -0
  23. package/lib/server/onboarding/index.js +256 -29
  24. package/lib/server/onboarding/workspace.js +38 -6
  25. package/lib/server/routes/onboarding.js +281 -12
  26. package/lib/server.js +11 -2
  27. package/package.json +1 -1
  28. package/lib/public/js/components/welcome.js +0 -318
@@ -1,318 +0,0 @@
1
- import { h } from "https://esm.sh/preact";
2
- import { useState, useEffect } from "https://esm.sh/preact/hooks";
3
- import htm from "https://esm.sh/htm";
4
- import {
5
- runOnboard,
6
- verifyGithubOnboardingRepo,
7
- fetchModels,
8
- } from "../lib/api.js";
9
- import {
10
- getModelProvider,
11
- getFeaturedModels,
12
- getVisibleAiFieldKeys,
13
- } from "../lib/model-config.js";
14
- import {
15
- kWelcomeGroups,
16
- isValidGithubRepoInput,
17
- } from "./onboarding/welcome-config.js";
18
- import { WelcomeHeader } from "./onboarding/welcome-header.js";
19
- import { WelcomeSetupStep } from "./onboarding/welcome-setup-step.js";
20
- import { WelcomeFormStep } from "./onboarding/welcome-form-step.js";
21
- import { WelcomePairingStep } from "./onboarding/welcome-pairing-step.js";
22
- import { getPreferredPairingChannel } from "./onboarding/pairing-utils.js";
23
- import {
24
- kOnboardingStorageKey,
25
- kPairingChannelKey,
26
- useWelcomeStorage,
27
- } from "./onboarding/use-welcome-storage.js";
28
- import { useWelcomeCodex } from "./onboarding/use-welcome-codex.js";
29
- import { useWelcomePairing } from "./onboarding/use-welcome-pairing.js";
30
- const html = htm.bind(h);
31
- const kMaxOnboardingVars = 64;
32
- const kMaxEnvKeyLength = 128;
33
- const kMaxEnvValueLength = 4096;
34
-
35
- export const Welcome = ({ onComplete }) => {
36
- const kSetupStepIndex = kWelcomeGroups.length;
37
- const kPairingStepIndex = kSetupStepIndex + 1;
38
- const { vals, setVals, setValue, step, setStep, setupError, setSetupError } =
39
- useWelcomeStorage({
40
- kSetupStepIndex,
41
- kPairingStepIndex,
42
- });
43
- const [models, setModels] = useState([]);
44
- const [modelsLoading, setModelsLoading] = useState(true);
45
- const [modelsError, setModelsError] = useState(null);
46
- const [showAllModels, setShowAllModels] = useState(false);
47
- const [loading, setLoading] = useState(false);
48
- const [githubStepLoading, setGithubStepLoading] = useState(false);
49
- const [formError, setFormError] = useState(null);
50
- const {
51
- codexStatus,
52
- codexLoading,
53
- codexManualInput,
54
- setCodexManualInput,
55
- codexExchanging,
56
- codexAuthStarted,
57
- codexAuthWaiting,
58
- startCodexAuth,
59
- completeCodexAuth,
60
- handleCodexDisconnect,
61
- } = useWelcomeCodex({ setFormError });
62
-
63
- useEffect(() => {
64
- fetchModels()
65
- .then((result) => {
66
- const list = Array.isArray(result.models) ? result.models : [];
67
- const featured = getFeaturedModels(list);
68
- setModels(list);
69
- if (!vals.MODEL_KEY && list.length > 0) {
70
- const defaultModel = featured[0] || list[0];
71
- setVals((prev) => ({ ...prev, MODEL_KEY: defaultModel.key }));
72
- }
73
- })
74
- .catch(() => setModelsError("Failed to load models"))
75
- .finally(() => setModelsLoading(false));
76
- }, []);
77
-
78
- const selectedProvider = getModelProvider(vals.MODEL_KEY);
79
- const featuredModels = getFeaturedModels(models);
80
- const baseModelOptions = showAllModels
81
- ? models
82
- : featuredModels.length > 0
83
- ? featuredModels
84
- : models;
85
- const selectedModelOption = models.find(
86
- (model) => model.key === vals.MODEL_KEY,
87
- );
88
- const modelOptions =
89
- selectedModelOption &&
90
- !baseModelOptions.some((model) => model.key === selectedModelOption.key)
91
- ? [...baseModelOptions, selectedModelOption]
92
- : baseModelOptions;
93
- const canToggleFullCatalog =
94
- featuredModels.length > 0 && models.length > featuredModels.length;
95
- const visibleAiFieldKeys = getVisibleAiFieldKeys(selectedProvider);
96
- const hasAi =
97
- selectedProvider === "anthropic"
98
- ? !!(vals.ANTHROPIC_API_KEY || vals.ANTHROPIC_TOKEN)
99
- : selectedProvider === "openai"
100
- ? !!vals.OPENAI_API_KEY
101
- : selectedProvider === "google"
102
- ? !!vals.GEMINI_API_KEY
103
- : selectedProvider === "openai-codex"
104
- ? !!codexStatus.connected
105
- : false;
106
-
107
- const allValid = kWelcomeGroups.every((g) => g.validate(vals, { hasAi }));
108
- const isSetupStep = step === kSetupStepIndex;
109
- const isPairingStep = step === kPairingStepIndex;
110
- const activeGroup = step < kSetupStepIndex ? kWelcomeGroups[step] : null;
111
- const currentGroupValid = activeGroup
112
- ? activeGroup.validate(vals, { hasAi })
113
- : false;
114
- const selectedPairingChannel = String(
115
- vals[kPairingChannelKey] || getPreferredPairingChannel(vals),
116
- );
117
- const {
118
- pairingStatusPoll,
119
- pairingRequestsPoll,
120
- pairingChannels,
121
- canFinishPairing,
122
- pairingError,
123
- pairingComplete,
124
- handlePairingApprove,
125
- handlePairingReject,
126
- resetPairingState,
127
- } = useWelcomePairing({
128
- isPairingStep,
129
- selectedPairingChannel,
130
- });
131
-
132
- const handleSubmit = async () => {
133
- if (!allValid || loading) return;
134
- const vars = Object.entries(vals)
135
- .filter(
136
- ([key]) => key !== "MODEL_KEY" && !String(key || "").startsWith("_"),
137
- )
138
- .filter(([, v]) => v)
139
- .map(([key, value]) => ({ key, value }));
140
- const preflightError = (() => {
141
- if (!vals.MODEL_KEY || !String(vals.MODEL_KEY).includes("/")) {
142
- return "A model selection is required";
143
- }
144
- if (vars.length > kMaxOnboardingVars) {
145
- return `Too many environment variables (max ${kMaxOnboardingVars})`;
146
- }
147
- for (const entry of vars) {
148
- const key = String(entry?.key || "");
149
- const value = String(entry?.value || "");
150
- if (!key) return "Each variable must include a key";
151
- if (key.length > kMaxEnvKeyLength) {
152
- return `Variable key is too long: ${key.slice(0, 32)}...`;
153
- }
154
- if (value.length > kMaxEnvValueLength) {
155
- return `Value too long for ${key} (max ${kMaxEnvValueLength} chars)`;
156
- }
157
- }
158
- if (!vals.GITHUB_TOKEN || !isValidGithubRepoInput(vals.GITHUB_WORKSPACE_REPO)) {
159
- return 'GITHUB_WORKSPACE_REPO must be in "owner/repo" format.';
160
- }
161
- return "";
162
- })();
163
- if (preflightError) {
164
- setFormError(preflightError);
165
- setSetupError(null);
166
- setStep(Math.max(0, kWelcomeGroups.findIndex((g) => g.id === "github")));
167
- return;
168
- }
169
- setStep(kSetupStepIndex);
170
- setLoading(true);
171
- setFormError(null);
172
- setSetupError(null);
173
- resetPairingState();
174
-
175
- try {
176
- const result = await runOnboard(vars, vals.MODEL_KEY);
177
- if (!result.ok) throw new Error(result.error || "Onboarding failed");
178
- const pairingChannel = getPreferredPairingChannel(vals);
179
- if (!pairingChannel) {
180
- throw new Error("No Telegram or Discord bot token configured for pairing.");
181
- }
182
- setVals((prev) => ({
183
- ...prev,
184
- [kPairingChannelKey]: pairingChannel,
185
- }));
186
- setLoading(false);
187
- setStep(kPairingStepIndex);
188
- resetPairingState();
189
- setSetupError(null);
190
- } catch (err) {
191
- console.error("Onboard error:", err);
192
- setSetupError(err.message || "Onboarding failed");
193
- setLoading(false);
194
- }
195
- };
196
-
197
- const finishOnboarding = () => {
198
- localStorage.removeItem(kOnboardingStorageKey);
199
- onComplete();
200
- };
201
-
202
- const goBack = () => {
203
- if (isSetupStep) return;
204
- setFormError(null);
205
- setStep((prev) => Math.max(0, prev - 1));
206
- };
207
- const goBackFromSetupError = () => {
208
- setLoading(false);
209
- setSetupError(null);
210
- setStep(kWelcomeGroups.length - 1);
211
- };
212
-
213
- const goNext = async () => {
214
- if (!activeGroup || !currentGroupValid) return;
215
- setFormError(null);
216
- if (activeGroup.id === "github") {
217
- setGithubStepLoading(true);
218
- try {
219
- const result = await verifyGithubOnboardingRepo(
220
- vals.GITHUB_WORKSPACE_REPO,
221
- vals.GITHUB_TOKEN,
222
- );
223
- if (!result?.ok) {
224
- setFormError(result?.error || "GitHub verification failed");
225
- return;
226
- }
227
- } catch (err) {
228
- setFormError(err?.message || "GitHub verification failed");
229
- return;
230
- } finally {
231
- setGithubStepLoading(false);
232
- }
233
- }
234
- setStep((prev) => Math.min(kWelcomeGroups.length - 1, prev + 1));
235
- };
236
-
237
- const activeStepLabel = isSetupStep
238
- ? "Initializing"
239
- : isPairingStep
240
- ? "Pairing"
241
- : activeGroup?.title || "Setup";
242
- const stepNumber = isSetupStep
243
- ? kWelcomeGroups.length + 1
244
- : isPairingStep
245
- ? kWelcomeGroups.length + 2
246
- : step + 1;
247
-
248
- return html`
249
- <div class="max-w-lg w-full space-y-5">
250
- <${WelcomeHeader}
251
- groups=${kWelcomeGroups}
252
- step=${step}
253
- isSetupStep=${isSetupStep}
254
- isPairingStep=${isPairingStep}
255
- stepNumber=${stepNumber}
256
- activeStepLabel=${activeStepLabel}
257
- />
258
-
259
- <div class="bg-surface border border-border rounded-xl p-4 space-y-3">
260
- ${isSetupStep
261
- ? html`<${WelcomeSetupStep}
262
- error=${setupError}
263
- loading=${loading}
264
- onRetry=${handleSubmit}
265
- onBack=${goBackFromSetupError}
266
- />`
267
- : isPairingStep
268
- ? html`<${WelcomePairingStep}
269
- channel=${selectedPairingChannel}
270
- pairings=${pairingRequestsPoll.data || []}
271
- channels=${pairingChannels}
272
- loading=${!pairingStatusPoll.data}
273
- error=${pairingError}
274
- onApprove=${handlePairingApprove}
275
- onReject=${handlePairingReject}
276
- canFinish=${pairingComplete || canFinishPairing}
277
- onContinue=${finishOnboarding}
278
- />`
279
- : html`
280
- <${WelcomeFormStep}
281
- activeGroup=${activeGroup}
282
- vals=${vals}
283
- hasAi=${hasAi}
284
- setValue=${setValue}
285
- modelOptions=${modelOptions}
286
- modelsLoading=${modelsLoading}
287
- modelsError=${modelsError}
288
- canToggleFullCatalog=${canToggleFullCatalog}
289
- showAllModels=${showAllModels}
290
- setShowAllModels=${setShowAllModels}
291
- selectedProvider=${selectedProvider}
292
- codexLoading=${codexLoading}
293
- codexStatus=${codexStatus}
294
- startCodexAuth=${startCodexAuth}
295
- handleCodexDisconnect=${handleCodexDisconnect}
296
- codexAuthStarted=${codexAuthStarted}
297
- codexAuthWaiting=${codexAuthWaiting}
298
- codexManualInput=${codexManualInput}
299
- setCodexManualInput=${setCodexManualInput}
300
- completeCodexAuth=${completeCodexAuth}
301
- codexExchanging=${codexExchanging}
302
- visibleAiFieldKeys=${visibleAiFieldKeys}
303
- error=${formError}
304
- step=${step}
305
- totalGroups=${kWelcomeGroups.length}
306
- currentGroupValid=${currentGroupValid}
307
- goBack=${goBack}
308
- goNext=${goNext}
309
- loading=${loading}
310
- githubStepLoading=${githubStepLoading}
311
- allValid=${allValid}
312
- handleSubmit=${handleSubmit}
313
- />
314
- `}
315
- </div>
316
- </div>
317
- `;
318
- };