@chrysb/alphaclaw 0.4.1-beta.0 → 0.4.1-beta.2
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/css/explorer.css +156 -4
- package/lib/public/js/components/file-tree.js +533 -48
- package/lib/public/js/components/file-viewer/index.js +2 -8
- package/lib/public/js/components/google/index.js +83 -48
- package/lib/public/js/components/icons.js +26 -0
- package/lib/public/js/components/onboarding/use-welcome-codex.js +129 -0
- package/lib/public/js/components/onboarding/use-welcome-pairing.js +74 -0
- package/lib/public/js/components/onboarding/use-welcome-storage.js +60 -0
- package/lib/public/js/components/sidebar.js +1 -1
- package/lib/public/js/components/telegram-workspace/onboarding.js +1 -1
- package/lib/public/js/components/webhooks.js +2 -2
- package/lib/public/js/components/welcome.js +57 -210
- package/lib/public/js/lib/api.js +27 -0
- package/lib/public/js/lib/browse-file-policies.js +3 -1
- package/lib/public/shared/browse-file-policies.json +2 -1
- package/lib/server/constants.js +0 -1
- package/lib/server/gmail-serve.js +1 -1
- package/lib/server/gmail-watch.js +8 -28
- package/lib/server/gog-skill.js +169 -0
- package/lib/server/onboarding/openclaw.js +9 -1
- package/lib/server/routes/browse/index.js +123 -6
- package/lib/server/routes/browse/path-utils.js +3 -1
- package/lib/server/routes/google.js +4 -0
- package/lib/server/routes/webhooks.js +3 -5
- package/lib/server/webhooks.js +1 -1
- package/lib/server.js +2 -0
- package/lib/setup/skills/gog-cli/calendar.md +63 -0
- package/lib/setup/skills/gog-cli/contacts.md +30 -0
- package/lib/setup/skills/gog-cli/docs.md +46 -0
- package/lib/setup/skills/gog-cli/drive.md +48 -0
- package/lib/setup/skills/gog-cli/gmail.md +64 -0
- package/lib/setup/skills/gog-cli/meet.md +6 -0
- package/lib/setup/skills/gog-cli/sheets.md +43 -0
- package/lib/setup/skills/gog-cli/tasks.md +32 -0
- package/package.json +2 -2
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import { h } from "https://esm.sh/preact";
|
|
2
|
-
import { useState, useEffect
|
|
2
|
+
import { useState, useEffect } from "https://esm.sh/preact/hooks";
|
|
3
3
|
import htm from "https://esm.sh/htm";
|
|
4
4
|
import {
|
|
5
5
|
runOnboard,
|
|
6
6
|
verifyGithubOnboardingRepo,
|
|
7
7
|
fetchModels,
|
|
8
|
-
fetchCodexStatus,
|
|
9
|
-
disconnectCodex,
|
|
10
|
-
exchangeCodexOAuth,
|
|
11
|
-
fetchStatus,
|
|
12
|
-
fetchPairings,
|
|
13
|
-
approvePairing,
|
|
14
|
-
rejectPairing,
|
|
15
8
|
} from "../lib/api.js";
|
|
16
|
-
import { usePolling } from "../hooks/usePolling.js";
|
|
17
9
|
import {
|
|
18
10
|
getModelProvider,
|
|
19
11
|
getFeaturedModels,
|
|
@@ -27,41 +19,46 @@ import { WelcomeHeader } from "./onboarding/welcome-header.js";
|
|
|
27
19
|
import { WelcomeSetupStep } from "./onboarding/welcome-setup-step.js";
|
|
28
20
|
import { WelcomeFormStep } from "./onboarding/welcome-form-step.js";
|
|
29
21
|
import { WelcomePairingStep } from "./onboarding/welcome-pairing-step.js";
|
|
22
|
+
import { getPreferredPairingChannel } from "./onboarding/pairing-utils.js";
|
|
30
23
|
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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";
|
|
34
30
|
const html = htm.bind(h);
|
|
35
|
-
const kOnboardingStorageKey = "openclaw_setup";
|
|
36
|
-
const kOnboardingStepKey = "_step";
|
|
37
|
-
const kPairingChannelKey = "_pairingChannel";
|
|
38
31
|
const kMaxOnboardingVars = 64;
|
|
39
32
|
const kMaxEnvKeyLength = 128;
|
|
40
33
|
const kMaxEnvValueLength = 4096;
|
|
41
34
|
|
|
42
35
|
export const Welcome = ({ onComplete }) => {
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const [vals, setVals] = useState(() => ({ ...initialSetupState }));
|
|
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
|
+
});
|
|
51
43
|
const [models, setModels] = useState([]);
|
|
52
44
|
const [modelsLoading, setModelsLoading] = useState(true);
|
|
53
45
|
const [modelsError, setModelsError] = useState(null);
|
|
54
46
|
const [showAllModels, setShowAllModels] = useState(false);
|
|
55
|
-
const [codexStatus, setCodexStatus] = useState({ connected: false });
|
|
56
|
-
const [codexLoading, setCodexLoading] = useState(true);
|
|
57
|
-
const [codexManualInput, setCodexManualInput] = useState("");
|
|
58
|
-
const [codexExchanging, setCodexExchanging] = useState(false);
|
|
59
|
-
const [codexAuthStarted, setCodexAuthStarted] = useState(false);
|
|
60
|
-
const [codexAuthWaiting, setCodexAuthWaiting] = useState(false);
|
|
61
47
|
const [loading, setLoading] = useState(false);
|
|
62
48
|
const [githubStepLoading, setGithubStepLoading] = useState(false);
|
|
63
|
-
const [
|
|
64
|
-
const
|
|
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 });
|
|
65
62
|
|
|
66
63
|
useEffect(() => {
|
|
67
64
|
fetchModels()
|
|
@@ -78,50 +75,6 @@ export const Welcome = ({ onComplete }) => {
|
|
|
78
75
|
.finally(() => setModelsLoading(false));
|
|
79
76
|
}, []);
|
|
80
77
|
|
|
81
|
-
const refreshCodexStatus = async () => {
|
|
82
|
-
try {
|
|
83
|
-
const status = await fetchCodexStatus();
|
|
84
|
-
setCodexStatus(status);
|
|
85
|
-
if (status?.connected) {
|
|
86
|
-
setCodexAuthStarted(false);
|
|
87
|
-
setCodexAuthWaiting(false);
|
|
88
|
-
}
|
|
89
|
-
} catch {
|
|
90
|
-
setCodexStatus({ connected: false });
|
|
91
|
-
} finally {
|
|
92
|
-
setCodexLoading(false);
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
useEffect(() => {
|
|
97
|
-
refreshCodexStatus();
|
|
98
|
-
}, []);
|
|
99
|
-
|
|
100
|
-
useEffect(() => {
|
|
101
|
-
const onMessage = async (e) => {
|
|
102
|
-
if (e.data?.codex === "success") {
|
|
103
|
-
await refreshCodexStatus();
|
|
104
|
-
}
|
|
105
|
-
if (e.data?.codex === "error") {
|
|
106
|
-
setError(`Codex auth failed: ${e.data.message || "unknown error"}`);
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
window.addEventListener("message", onMessage);
|
|
110
|
-
return () => window.removeEventListener("message", onMessage);
|
|
111
|
-
}, []);
|
|
112
|
-
|
|
113
|
-
useEffect(
|
|
114
|
-
() => () => {
|
|
115
|
-
if (codexPopupPollRef.current) {
|
|
116
|
-
clearInterval(codexPopupPollRef.current);
|
|
117
|
-
codexPopupPollRef.current = null;
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
[],
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
const set = (key, value) => setVals((prev) => ({ ...prev, [key]: value }));
|
|
124
|
-
|
|
125
78
|
const selectedProvider = getModelProvider(vals.MODEL_KEY);
|
|
126
79
|
const featuredModels = getFeaturedModels(models);
|
|
127
80
|
const baseModelOptions = showAllModels
|
|
@@ -152,18 +105,6 @@ export const Welcome = ({ onComplete }) => {
|
|
|
152
105
|
: false;
|
|
153
106
|
|
|
154
107
|
const allValid = kWelcomeGroups.every((g) => g.validate(vals, { hasAi }));
|
|
155
|
-
const kSetupStepIndex = kWelcomeGroups.length;
|
|
156
|
-
const kPairingStepIndex = kSetupStepIndex + 1;
|
|
157
|
-
const [step, setStep] = useState(() => {
|
|
158
|
-
const parsedStep = Number.parseInt(
|
|
159
|
-
String(initialSetupState?.[kOnboardingStepKey] || ""),
|
|
160
|
-
10,
|
|
161
|
-
);
|
|
162
|
-
if (!Number.isFinite(parsedStep)) return 0;
|
|
163
|
-
return Math.max(0, Math.min(kPairingStepIndex, parsedStep));
|
|
164
|
-
});
|
|
165
|
-
const [pairingError, setPairingError] = useState(null);
|
|
166
|
-
const [pairingComplete, setPairingComplete] = useState(false);
|
|
167
108
|
const isSetupStep = step === kSetupStepIndex;
|
|
168
109
|
const isPairingStep = step === kPairingStepIndex;
|
|
169
110
|
const activeGroup = step < kSetupStepIndex ? kWelcomeGroups[step] : null;
|
|
@@ -173,94 +114,20 @@ export const Welcome = ({ onComplete }) => {
|
|
|
173
114
|
const selectedPairingChannel = String(
|
|
174
115
|
vals[kPairingChannelKey] || getPreferredPairingChannel(vals),
|
|
175
116
|
);
|
|
176
|
-
const
|
|
177
|
-
|
|
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,
|
|
178
130
|
});
|
|
179
|
-
const pairingRequestsPoll = usePolling(
|
|
180
|
-
async () => {
|
|
181
|
-
const payload = await fetchPairings();
|
|
182
|
-
const allPending = payload.pending || [];
|
|
183
|
-
return allPending.filter((p) => p.channel === selectedPairingChannel);
|
|
184
|
-
},
|
|
185
|
-
1000,
|
|
186
|
-
{ enabled: isPairingStep && !!selectedPairingChannel },
|
|
187
|
-
);
|
|
188
|
-
const pairingChannels = pairingStatusPoll.data?.channels || {};
|
|
189
|
-
const canFinishPairing = isChannelPaired(pairingChannels, selectedPairingChannel);
|
|
190
|
-
|
|
191
|
-
useEffect(() => {
|
|
192
|
-
if (isPairingStep && canFinishPairing) {
|
|
193
|
-
setPairingComplete(true);
|
|
194
|
-
}
|
|
195
|
-
}, [isPairingStep, canFinishPairing]);
|
|
196
|
-
|
|
197
|
-
useEffect(() => {
|
|
198
|
-
localStorage.setItem(
|
|
199
|
-
kOnboardingStorageKey,
|
|
200
|
-
JSON.stringify({
|
|
201
|
-
...vals,
|
|
202
|
-
[kOnboardingStepKey]: step,
|
|
203
|
-
}),
|
|
204
|
-
);
|
|
205
|
-
}, [vals, step]);
|
|
206
|
-
|
|
207
|
-
const startCodexAuth = () => {
|
|
208
|
-
if (codexStatus.connected) return;
|
|
209
|
-
setCodexAuthStarted(true);
|
|
210
|
-
setCodexAuthWaiting(true);
|
|
211
|
-
const authUrl = "/auth/codex/start";
|
|
212
|
-
const popup = window.open(
|
|
213
|
-
authUrl,
|
|
214
|
-
"codex-auth",
|
|
215
|
-
"popup=yes,width=640,height=780",
|
|
216
|
-
);
|
|
217
|
-
if (!popup || popup.closed) {
|
|
218
|
-
setCodexAuthWaiting(false);
|
|
219
|
-
window.location.href = authUrl;
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
if (codexPopupPollRef.current) {
|
|
223
|
-
clearInterval(codexPopupPollRef.current);
|
|
224
|
-
}
|
|
225
|
-
codexPopupPollRef.current = setInterval(() => {
|
|
226
|
-
if (popup.closed) {
|
|
227
|
-
clearInterval(codexPopupPollRef.current);
|
|
228
|
-
codexPopupPollRef.current = null;
|
|
229
|
-
setCodexAuthWaiting(false);
|
|
230
|
-
}
|
|
231
|
-
}, 500);
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
const completeCodexAuth = async () => {
|
|
235
|
-
if (!codexManualInput.trim() || codexExchanging) return;
|
|
236
|
-
setCodexExchanging(true);
|
|
237
|
-
setError(null);
|
|
238
|
-
try {
|
|
239
|
-
const result = await exchangeCodexOAuth(codexManualInput.trim());
|
|
240
|
-
if (!result.ok)
|
|
241
|
-
throw new Error(result.error || "Codex OAuth exchange failed");
|
|
242
|
-
setCodexManualInput("");
|
|
243
|
-
setCodexAuthStarted(false);
|
|
244
|
-
setCodexAuthWaiting(false);
|
|
245
|
-
await refreshCodexStatus();
|
|
246
|
-
} catch (err) {
|
|
247
|
-
setError(err.message || "Codex OAuth exchange failed");
|
|
248
|
-
} finally {
|
|
249
|
-
setCodexExchanging(false);
|
|
250
|
-
}
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
const handleCodexDisconnect = async () => {
|
|
254
|
-
const result = await disconnectCodex();
|
|
255
|
-
if (!result.ok) {
|
|
256
|
-
setError(result.error || "Failed to disconnect Codex");
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
setCodexAuthStarted(false);
|
|
260
|
-
setCodexAuthWaiting(false);
|
|
261
|
-
setCodexManualInput("");
|
|
262
|
-
await refreshCodexStatus();
|
|
263
|
-
};
|
|
264
131
|
|
|
265
132
|
const handleSubmit = async () => {
|
|
266
133
|
if (!allValid || loading) return;
|
|
@@ -294,14 +161,16 @@ export const Welcome = ({ onComplete }) => {
|
|
|
294
161
|
return "";
|
|
295
162
|
})();
|
|
296
163
|
if (preflightError) {
|
|
297
|
-
|
|
164
|
+
setFormError(preflightError);
|
|
165
|
+
setSetupError(null);
|
|
298
166
|
setStep(Math.max(0, kWelcomeGroups.findIndex((g) => g.id === "github")));
|
|
299
167
|
return;
|
|
300
168
|
}
|
|
301
169
|
setStep(kSetupStepIndex);
|
|
302
170
|
setLoading(true);
|
|
303
|
-
|
|
304
|
-
|
|
171
|
+
setFormError(null);
|
|
172
|
+
setSetupError(null);
|
|
173
|
+
resetPairingState();
|
|
305
174
|
|
|
306
175
|
try {
|
|
307
176
|
const result = await runOnboard(vars, vals.MODEL_KEY);
|
|
@@ -316,38 +185,15 @@ export const Welcome = ({ onComplete }) => {
|
|
|
316
185
|
}));
|
|
317
186
|
setLoading(false);
|
|
318
187
|
setStep(kPairingStepIndex);
|
|
319
|
-
|
|
188
|
+
resetPairingState();
|
|
189
|
+
setSetupError(null);
|
|
320
190
|
} catch (err) {
|
|
321
191
|
console.error("Onboard error:", err);
|
|
322
|
-
|
|
192
|
+
setSetupError(err.message || "Onboarding failed");
|
|
323
193
|
setLoading(false);
|
|
324
194
|
}
|
|
325
195
|
};
|
|
326
196
|
|
|
327
|
-
const handlePairingApprove = async (id, channel) => {
|
|
328
|
-
try {
|
|
329
|
-
setPairingError(null);
|
|
330
|
-
const result = await approvePairing(id, channel);
|
|
331
|
-
if (!result.ok) throw new Error(result.error || "Could not approve pairing");
|
|
332
|
-
setPairingComplete(true);
|
|
333
|
-
pairingRequestsPoll.refresh();
|
|
334
|
-
pairingStatusPoll.refresh();
|
|
335
|
-
} catch (err) {
|
|
336
|
-
setPairingError(err.message || "Could not approve pairing");
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
const handlePairingReject = async (id, channel) => {
|
|
341
|
-
try {
|
|
342
|
-
setPairingError(null);
|
|
343
|
-
const result = await rejectPairing(id, channel);
|
|
344
|
-
if (!result.ok) throw new Error(result.error || "Could not reject pairing");
|
|
345
|
-
pairingRequestsPoll.refresh();
|
|
346
|
-
} catch (err) {
|
|
347
|
-
setPairingError(err.message || "Could not reject pairing");
|
|
348
|
-
}
|
|
349
|
-
};
|
|
350
|
-
|
|
351
197
|
const finishOnboarding = () => {
|
|
352
198
|
localStorage.removeItem(kOnboardingStorageKey);
|
|
353
199
|
onComplete();
|
|
@@ -355,17 +201,18 @@ export const Welcome = ({ onComplete }) => {
|
|
|
355
201
|
|
|
356
202
|
const goBack = () => {
|
|
357
203
|
if (isSetupStep) return;
|
|
358
|
-
|
|
204
|
+
setFormError(null);
|
|
359
205
|
setStep((prev) => Math.max(0, prev - 1));
|
|
360
206
|
};
|
|
361
207
|
const goBackFromSetupError = () => {
|
|
362
208
|
setLoading(false);
|
|
209
|
+
setSetupError(null);
|
|
363
210
|
setStep(kWelcomeGroups.length - 1);
|
|
364
211
|
};
|
|
365
212
|
|
|
366
213
|
const goNext = async () => {
|
|
367
214
|
if (!activeGroup || !currentGroupValid) return;
|
|
368
|
-
|
|
215
|
+
setFormError(null);
|
|
369
216
|
if (activeGroup.id === "github") {
|
|
370
217
|
setGithubStepLoading(true);
|
|
371
218
|
try {
|
|
@@ -374,11 +221,11 @@ export const Welcome = ({ onComplete }) => {
|
|
|
374
221
|
vals.GITHUB_TOKEN,
|
|
375
222
|
);
|
|
376
223
|
if (!result?.ok) {
|
|
377
|
-
|
|
224
|
+
setFormError(result?.error || "GitHub verification failed");
|
|
378
225
|
return;
|
|
379
226
|
}
|
|
380
227
|
} catch (err) {
|
|
381
|
-
|
|
228
|
+
setFormError(err?.message || "GitHub verification failed");
|
|
382
229
|
return;
|
|
383
230
|
} finally {
|
|
384
231
|
setGithubStepLoading(false);
|
|
@@ -412,7 +259,7 @@ export const Welcome = ({ onComplete }) => {
|
|
|
412
259
|
<div class="bg-surface border border-border rounded-xl p-4 space-y-3">
|
|
413
260
|
${isSetupStep
|
|
414
261
|
? html`<${WelcomeSetupStep}
|
|
415
|
-
error=${
|
|
262
|
+
error=${setupError}
|
|
416
263
|
loading=${loading}
|
|
417
264
|
onRetry=${handleSubmit}
|
|
418
265
|
onBack=${goBackFromSetupError}
|
|
@@ -434,7 +281,7 @@ export const Welcome = ({ onComplete }) => {
|
|
|
434
281
|
activeGroup=${activeGroup}
|
|
435
282
|
vals=${vals}
|
|
436
283
|
hasAi=${hasAi}
|
|
437
|
-
setValue=${
|
|
284
|
+
setValue=${setValue}
|
|
438
285
|
modelOptions=${modelOptions}
|
|
439
286
|
modelsLoading=${modelsLoading}
|
|
440
287
|
modelsError=${modelsError}
|
|
@@ -453,7 +300,7 @@ export const Welcome = ({ onComplete }) => {
|
|
|
453
300
|
completeCodexAuth=${completeCodexAuth}
|
|
454
301
|
codexExchanging=${codexExchanging}
|
|
455
302
|
visibleAiFieldKeys=${visibleAiFieldKeys}
|
|
456
|
-
error=${
|
|
303
|
+
error=${formError}
|
|
457
304
|
step=${step}
|
|
458
305
|
totalGroups=${kWelcomeGroups.length}
|
|
459
306
|
currentGroupValid=${currentGroupValid}
|
package/lib/public/js/lib/api.js
CHANGED
|
@@ -540,6 +540,33 @@ export const saveFileContent = async (filePath, content) => {
|
|
|
540
540
|
return parseJsonOrThrow(res, 'Could not save file');
|
|
541
541
|
};
|
|
542
542
|
|
|
543
|
+
export const createBrowseFile = async (filePath) => {
|
|
544
|
+
const res = await authFetch('/api/browse/create-file', {
|
|
545
|
+
method: 'POST',
|
|
546
|
+
headers: { 'Content-Type': 'application/json' },
|
|
547
|
+
body: JSON.stringify({ path: String(filePath || '') }),
|
|
548
|
+
});
|
|
549
|
+
return parseJsonOrThrow(res, 'Could not create file');
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
export const createBrowseFolder = async (folderPath) => {
|
|
553
|
+
const res = await authFetch('/api/browse/create-folder', {
|
|
554
|
+
method: 'POST',
|
|
555
|
+
headers: { 'Content-Type': 'application/json' },
|
|
556
|
+
body: JSON.stringify({ path: String(folderPath || '') }),
|
|
557
|
+
});
|
|
558
|
+
return parseJsonOrThrow(res, 'Could not create folder');
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
export const moveBrowsePath = async (from, to) => {
|
|
562
|
+
const res = await authFetch('/api/browse/move', {
|
|
563
|
+
method: 'POST',
|
|
564
|
+
headers: { 'Content-Type': 'application/json' },
|
|
565
|
+
body: JSON.stringify({ from: String(from || ''), to: String(to || '') }),
|
|
566
|
+
});
|
|
567
|
+
return parseJsonOrThrow(res, 'Could not move path');
|
|
568
|
+
};
|
|
569
|
+
|
|
543
570
|
export const deleteBrowseFile = async (filePath) => {
|
|
544
571
|
const res = await authFetch('/api/browse/delete', {
|
|
545
572
|
method: 'DELETE',
|
|
@@ -43,7 +43,9 @@ export const matchesBrowsePolicyPath = (policyPathSet, normalizedPath) => {
|
|
|
43
43
|
for (const policyPath of policyPathSet) {
|
|
44
44
|
if (
|
|
45
45
|
safeNormalizedPath === policyPath ||
|
|
46
|
-
safeNormalizedPath.endsWith(`/${policyPath}`)
|
|
46
|
+
safeNormalizedPath.endsWith(`/${policyPath}`) ||
|
|
47
|
+
safeNormalizedPath.startsWith(`${policyPath}/`) ||
|
|
48
|
+
safeNormalizedPath.includes(`/${policyPath}/`)
|
|
47
49
|
) {
|
|
48
50
|
return true;
|
|
49
51
|
}
|
package/lib/server/constants.js
CHANGED
|
@@ -110,7 +110,7 @@ const createGmailServeManager = ({
|
|
|
110
110
|
}
|
|
111
111
|
const token = String(webhookToken || "").trim();
|
|
112
112
|
if (!token) {
|
|
113
|
-
throw new Error("
|
|
113
|
+
throw new Error("WEBHOOK_TOKEN is required to start Gmail watch serve");
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
const args = buildArgs({ account, port: normalizedPort, webhookToken: token });
|
|
@@ -203,39 +203,19 @@ const createGmailWatchService = ({
|
|
|
203
203
|
};
|
|
204
204
|
|
|
205
205
|
const ensureWebhookToken = () => {
|
|
206
|
-
const existing = String(
|
|
207
|
-
process.env.OPENCLAW_HOOKS_TOKEN || process.env.WEBHOOK_TOKEN || "",
|
|
208
|
-
).trim();
|
|
206
|
+
const existing = String(process.env.WEBHOOK_TOKEN || "").trim();
|
|
209
207
|
if (existing) return { token: existing, changed: false };
|
|
210
208
|
const vars = readEnvFile();
|
|
211
|
-
const
|
|
212
|
-
vars.find((entry) => entry.key === "OPENCLAW_HOOKS_TOKEN")?.value || "",
|
|
213
|
-
).trim();
|
|
214
|
-
const tokenFromLegacyWebhook = String(
|
|
209
|
+
const tokenFromFile = String(
|
|
215
210
|
vars.find((entry) => entry.key === "WEBHOOK_TOKEN")?.value || "",
|
|
216
211
|
).trim();
|
|
217
|
-
const tokenFromFile = tokenFromOpenclawHooks || tokenFromLegacyWebhook;
|
|
218
212
|
if (tokenFromFile) {
|
|
219
|
-
process.env.
|
|
220
|
-
if (!process.env.WEBHOOK_TOKEN) {
|
|
221
|
-
process.env.WEBHOOK_TOKEN = tokenFromFile;
|
|
222
|
-
}
|
|
223
|
-
if (!tokenFromOpenclawHooks) {
|
|
224
|
-
const nextVars = vars.filter(
|
|
225
|
-
(entry) => entry.key !== "OPENCLAW_HOOKS_TOKEN",
|
|
226
|
-
);
|
|
227
|
-
nextVars.push({ key: "OPENCLAW_HOOKS_TOKEN", value: tokenFromFile });
|
|
228
|
-
writeEnvFile(nextVars);
|
|
229
|
-
reloadEnv();
|
|
230
|
-
return { token: tokenFromFile, changed: true };
|
|
231
|
-
}
|
|
213
|
+
process.env.WEBHOOK_TOKEN = tokenFromFile;
|
|
232
214
|
return { token: tokenFromFile, changed: false };
|
|
233
215
|
}
|
|
234
216
|
const token = generatePushToken();
|
|
235
|
-
const nextVars = vars.filter(
|
|
236
|
-
|
|
237
|
-
);
|
|
238
|
-
nextVars.push({ key: "OPENCLAW_HOOKS_TOKEN", value: token });
|
|
217
|
+
const nextVars = vars.filter((entry) => entry.key !== "WEBHOOK_TOKEN");
|
|
218
|
+
nextVars.push({ key: "WEBHOOK_TOKEN", value: token });
|
|
239
219
|
writeEnvFile(nextVars);
|
|
240
220
|
reloadEnv();
|
|
241
221
|
return { token, changed: true };
|
|
@@ -258,7 +238,7 @@ const createGmailWatchService = ({
|
|
|
258
238
|
changed = true;
|
|
259
239
|
}
|
|
260
240
|
if (typeof cfg.hooks.token !== "string" || !cfg.hooks.token.trim()) {
|
|
261
|
-
cfg.hooks.token = "${
|
|
241
|
+
cfg.hooks.token = "${WEBHOOK_TOKEN}";
|
|
262
242
|
changed = true;
|
|
263
243
|
}
|
|
264
244
|
if (!Array.isArray(cfg.hooks.presets)) {
|
|
@@ -337,7 +317,7 @@ const createGmailWatchService = ({
|
|
|
337
317
|
const watch = getAccountGmailWatch(account || {});
|
|
338
318
|
if (!account || !watch.enabled || !watch.port) return;
|
|
339
319
|
const token = String(
|
|
340
|
-
process.env.
|
|
320
|
+
process.env.WEBHOOK_TOKEN || "",
|
|
341
321
|
).trim();
|
|
342
322
|
if (!token) return;
|
|
343
323
|
const status = await serveManager.startServe({
|
|
@@ -633,7 +613,7 @@ const createGmailWatchService = ({
|
|
|
633
613
|
try {
|
|
634
614
|
let state = readState();
|
|
635
615
|
const hookToken = String(
|
|
636
|
-
process.env.
|
|
616
|
+
process.env.WEBHOOK_TOKEN || "",
|
|
637
617
|
).trim();
|
|
638
618
|
const enabled = listWatchEnabledAccounts(state);
|
|
639
619
|
for (const account of enabled) {
|