@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.
- package/bin/alphaclaw.js +2 -32
- package/lib/public/css/theme.css +19 -0
- package/lib/public/js/app.js +1 -1
- package/lib/public/js/components/envars.js +0 -1
- package/lib/public/js/components/onboarding/welcome-config.js +39 -17
- package/lib/public/js/components/onboarding/welcome-form-step.js +142 -47
- package/lib/public/js/components/onboarding/welcome-import-step.js +306 -0
- package/lib/public/js/components/onboarding/welcome-placeholder-review-step.js +99 -0
- package/lib/public/js/components/onboarding/welcome-secret-review-step.js +191 -0
- package/lib/public/js/components/segmented-control.js +7 -1
- package/lib/public/js/components/welcome/index.js +112 -0
- package/lib/public/js/components/welcome/use-welcome.js +561 -0
- package/lib/public/js/lib/api.js +221 -161
- package/lib/server/commands.js +1 -0
- package/lib/server/constants.js +0 -1
- package/lib/server/gateway.js +15 -40
- package/lib/server/onboarding/github.js +120 -19
- package/lib/server/onboarding/import/import-applier.js +321 -0
- package/lib/server/onboarding/import/import-config.js +69 -0
- package/lib/server/onboarding/import/import-scanner.js +469 -0
- package/lib/server/onboarding/import/import-temp.js +63 -0
- package/lib/server/onboarding/import/secret-detector.js +289 -0
- package/lib/server/onboarding/index.js +256 -29
- package/lib/server/onboarding/workspace.js +38 -6
- package/lib/server/routes/onboarding.js +281 -12
- package/lib/server.js +11 -2
- package/package.json +1 -1
- 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
|
-
};
|