@chrysb/alphaclaw 0.4.1-beta.0 → 0.4.1-beta.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/lib/public/js/components/google/index.js +83 -48
- 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/server/constants.js +0 -1
- package/lib/server/gmail-serve.js +1 -1
- package/lib/server/gmail-watch.js +8 -28
- package/lib/server/onboarding/openclaw.js +9 -1
- package/lib/server/routes/webhooks.js +3 -5
- package/lib/server/webhooks.js +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { h } from "https://esm.sh/preact";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useMemo,
|
|
6
|
+
useState,
|
|
7
|
+
} from "https://esm.sh/preact/hooks";
|
|
3
8
|
import htm from "https://esm.sh/htm";
|
|
4
9
|
import {
|
|
5
10
|
checkGoogleApis,
|
|
@@ -34,12 +39,8 @@ export const Google = ({
|
|
|
34
39
|
onRestartRequired = () => {},
|
|
35
40
|
onOpenGmailWebhook = () => {},
|
|
36
41
|
}) => {
|
|
37
|
-
const {
|
|
38
|
-
|
|
39
|
-
loading,
|
|
40
|
-
hasCompanyCredentials,
|
|
41
|
-
refreshAccounts,
|
|
42
|
-
} = useGoogleAccounts({ gatewayStatus });
|
|
42
|
+
const { accounts, loading, hasCompanyCredentials, refreshAccounts } =
|
|
43
|
+
useGoogleAccounts({ gatewayStatus });
|
|
43
44
|
const [expandedAccountId, setExpandedAccountId] = useState("");
|
|
44
45
|
const [scopesByAccountId, setScopesByAccountId] = useState({});
|
|
45
46
|
const [savedScopesByAccountId, setSavedScopesByAccountId] = useState({});
|
|
@@ -90,12 +91,16 @@ export const Google = ({
|
|
|
90
91
|
);
|
|
91
92
|
|
|
92
93
|
const ensureScopesForAccount = useCallback((account) => {
|
|
93
|
-
const nextScopes =
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
const nextScopes =
|
|
95
|
+
Array.isArray(account.activeScopes) && account.activeScopes.length
|
|
96
|
+
? account.activeScopes
|
|
97
|
+
: Array.isArray(account.services) && account.services.length
|
|
98
|
+
? account.services
|
|
99
|
+
: getDefaultScopes();
|
|
100
|
+
setSavedScopesByAccountId((prev) => ({
|
|
101
|
+
...prev,
|
|
102
|
+
[account.id]: [...nextScopes],
|
|
103
|
+
}));
|
|
99
104
|
setScopesByAccountId((prev) => {
|
|
100
105
|
const current = prev[account.id];
|
|
101
106
|
if (!current || !hasScopesChanged(current, nextScopes)) {
|
|
@@ -125,7 +130,10 @@ export const Google = ({
|
|
|
125
130
|
(accountId) => {
|
|
126
131
|
const account = getAccountById(accountId);
|
|
127
132
|
if (!account) return;
|
|
128
|
-
const scopes =
|
|
133
|
+
const scopes =
|
|
134
|
+
scopesByAccountId[accountId] ||
|
|
135
|
+
account.activeScopes ||
|
|
136
|
+
getDefaultScopes();
|
|
129
137
|
if (!scopes.length) {
|
|
130
138
|
window.alert("Select at least one service");
|
|
131
139
|
return;
|
|
@@ -160,7 +168,10 @@ export const Google = ({
|
|
|
160
168
|
try {
|
|
161
169
|
const data = await checkGoogleApis(accountId);
|
|
162
170
|
if (data.results) {
|
|
163
|
-
setApiStatusByAccountId((prev) => ({
|
|
171
|
+
setApiStatusByAccountId((prev) => ({
|
|
172
|
+
...prev,
|
|
173
|
+
[accountId]: data.results,
|
|
174
|
+
}));
|
|
164
175
|
}
|
|
165
176
|
} finally {
|
|
166
177
|
setCheckingByAccountId((prev) => {
|
|
@@ -184,7 +195,10 @@ export const Google = ({
|
|
|
184
195
|
await handleCheckApis(accountId);
|
|
185
196
|
}
|
|
186
197
|
} else if (event.data?.google === "error") {
|
|
187
|
-
showToast(
|
|
198
|
+
showToast(
|
|
199
|
+
`✗ Google auth failed: ${event.data.message || "unknown"}`,
|
|
200
|
+
"error",
|
|
201
|
+
);
|
|
188
202
|
}
|
|
189
203
|
};
|
|
190
204
|
window.addEventListener("message", handler);
|
|
@@ -249,6 +263,9 @@ export const Google = ({
|
|
|
249
263
|
};
|
|
250
264
|
|
|
251
265
|
const handleCredentialsSaved = async (account) => {
|
|
266
|
+
if (account?.id) {
|
|
267
|
+
setExpandedAccountId(account.id);
|
|
268
|
+
}
|
|
252
269
|
await refreshAccounts();
|
|
253
270
|
if (account?.id) startAuth(account.id);
|
|
254
271
|
};
|
|
@@ -267,6 +284,9 @@ export const Google = ({
|
|
|
267
284
|
return;
|
|
268
285
|
}
|
|
269
286
|
setAddCompanyModalOpen(false);
|
|
287
|
+
if (data.accountId) {
|
|
288
|
+
setExpandedAccountId(data.accountId);
|
|
289
|
+
}
|
|
270
290
|
await refreshAccounts();
|
|
271
291
|
if (data.accountId) startAuth(data.accountId);
|
|
272
292
|
} finally {
|
|
@@ -304,7 +324,7 @@ export const Google = ({
|
|
|
304
324
|
const account = getAccountById(accountId);
|
|
305
325
|
if (!account) return;
|
|
306
326
|
const personal = isPersonalAccount(account);
|
|
307
|
-
const client = personal ? "personal" :
|
|
327
|
+
const client = personal ? "personal" : account.client || "default";
|
|
308
328
|
let credentialValues = {};
|
|
309
329
|
try {
|
|
310
330
|
const credentialResponse = await fetchGoogleCredentials({
|
|
@@ -390,22 +410,23 @@ export const Google = ({
|
|
|
390
410
|
};
|
|
391
411
|
|
|
392
412
|
const renderEmptyState = () => html`
|
|
393
|
-
<div class="text-center space-y-2
|
|
413
|
+
<div class="text-center space-y-2 pt-3">
|
|
394
414
|
<div class="rounded-lg border border-border bg-black/20 px-3 py-5">
|
|
395
|
-
<div class="flex flex-col items-center justify-center gap-
|
|
415
|
+
<div class="flex flex-col items-center justify-center gap-3">
|
|
396
416
|
<img
|
|
397
417
|
src=${kGoogleIconPath}
|
|
398
418
|
alt="Google logo"
|
|
399
|
-
class="h-
|
|
419
|
+
class="h-5 w-5 shrink-0"
|
|
400
420
|
loading="lazy"
|
|
401
421
|
decoding="async"
|
|
402
422
|
/>
|
|
403
423
|
<p class="text-xs text-gray-500">
|
|
404
|
-
Connect Gmail, Calendar, Contacts, Drive, Sheets, Tasks, Docs, and
|
|
424
|
+
Connect Gmail, Calendar, Contacts, Drive, Sheets, Tasks, Docs, and
|
|
425
|
+
Meet.
|
|
405
426
|
</p>
|
|
406
427
|
</div>
|
|
407
428
|
</div>
|
|
408
|
-
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
|
429
|
+
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2 pt-2">
|
|
409
430
|
<${ActionButton}
|
|
410
431
|
onClick=${handleAddCompanyClick}
|
|
411
432
|
tone="primary"
|
|
@@ -469,34 +490,46 @@ export const Google = ({
|
|
|
469
490
|
`}
|
|
470
491
|
/>
|
|
471
492
|
${loading
|
|
472
|
-
? html`<div class="text-gray-500 text-sm text-center py-2">
|
|
493
|
+
? html`<div class="text-gray-500 text-sm text-center py-2">
|
|
494
|
+
Loading...
|
|
495
|
+
</div>`
|
|
473
496
|
: accounts.length
|
|
474
497
|
? html`
|
|
475
498
|
<div class="space-y-2 mt-3">
|
|
476
|
-
${accounts.map(
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
499
|
+
${accounts.map(
|
|
500
|
+
(account) =>
|
|
501
|
+
html`<${GoogleAccountRow}
|
|
502
|
+
key=${account.id}
|
|
503
|
+
account=${account}
|
|
504
|
+
personal=${isPersonalAccount(account)}
|
|
505
|
+
expanded=${expandedAccountId === account.id}
|
|
506
|
+
onToggleExpanded=${(accountId) =>
|
|
507
|
+
setExpandedAccountId((prev) =>
|
|
508
|
+
prev === accountId ? "" : accountId,
|
|
509
|
+
)}
|
|
510
|
+
scopes=${scopesByAccountId[account.id] ||
|
|
511
|
+
account.activeScopes ||
|
|
512
|
+
getDefaultScopes()}
|
|
513
|
+
savedScopes=${savedScopesByAccountId[account.id] ||
|
|
514
|
+
account.activeScopes ||
|
|
515
|
+
getDefaultScopes()}
|
|
516
|
+
apiStatus=${apiStatusByAccountId[account.id] || {}}
|
|
517
|
+
checkingApis=${expandedAccountId === account.id &&
|
|
518
|
+
Boolean(checkingByAccountId[account.id])}
|
|
519
|
+
onToggleScope=${handleToggleScope}
|
|
520
|
+
onCheckApis=${handleCheckApis}
|
|
521
|
+
onUpdatePermissions=${(accountId) => startAuth(accountId)}
|
|
522
|
+
onEditCredentials=${handleEditCredentials}
|
|
523
|
+
onDisconnect=${(accountId) =>
|
|
524
|
+
setDisconnectAccountId(accountId)}
|
|
525
|
+
gmailWatchStatus=${watchByAccountId.get(account.id) ||
|
|
526
|
+
null}
|
|
527
|
+
gmailWatchBusy=${Boolean(busyByAccountId[account.id])}
|
|
528
|
+
onEnableGmailWatch=${handleEnableGmailWatch}
|
|
529
|
+
onDisableGmailWatch=${handleDisableGmailWatch}
|
|
530
|
+
onOpenGmailSetup=${openGmailSetupWizard}
|
|
531
|
+
onOpenGmailWebhook=${onOpenGmailWebhook}
|
|
532
|
+
/>`,
|
|
500
533
|
)}
|
|
501
534
|
</div>
|
|
502
535
|
`
|
|
@@ -528,7 +561,9 @@ export const Google = ({
|
|
|
528
561
|
visible=${gmailWizardState.visible}
|
|
529
562
|
account=${getAccountById(gmailWizardState.accountId)}
|
|
530
563
|
clientConfig=${clientConfigByClient.get(
|
|
531
|
-
String(
|
|
564
|
+
String(
|
|
565
|
+
getAccountById(gmailWizardState.accountId)?.client || "default",
|
|
566
|
+
).trim() || "default",
|
|
532
567
|
) || null}
|
|
533
568
|
saving=${savingClient || gmailLoading}
|
|
534
569
|
onClose=${closeGmailSetupWizard}
|
|
@@ -12,7 +12,7 @@ const kBrowseBottomPanelUiSettingKey = "browseBottomPanelHeightPx";
|
|
|
12
12
|
const kBrowsePanelMinHeightPx = 120;
|
|
13
13
|
const kBrowseBottomMinHeightPx = 120;
|
|
14
14
|
const kBrowseResizerHeightPx = 6;
|
|
15
|
-
const kDefaultBrowseBottomPanelHeightPx =
|
|
15
|
+
const kDefaultBrowseBottomPanelHeightPx = 260;
|
|
16
16
|
|
|
17
17
|
const readStoredBrowseBottomPanelHeight = () => {
|
|
18
18
|
try {
|
|
@@ -116,7 +116,7 @@ export const CreateGroupStep = ({ onNext, onBack }) => html`
|
|
|
116
116
|
<p class="text-xs font-medium text-gray-300">Create the group</p>
|
|
117
117
|
<ol class="text-xs text-gray-400 space-y-2 list-decimal list-inside">
|
|
118
118
|
<li>
|
|
119
|
-
Open Telegram and create a
|
|
119
|
+
Open Telegram and create a${" "}
|
|
120
120
|
<span class="text-gray-300">new group</span>
|
|
121
121
|
</li>
|
|
122
122
|
<li>
|
|
@@ -232,7 +232,7 @@ export const Webhooks = ({
|
|
|
232
232
|
selectedWebhook?.fullUrl || `.../hooks/${selectedHookName}`;
|
|
233
233
|
const webhookUrlWithQueryToken =
|
|
234
234
|
selectedWebhook?.queryStringUrl ||
|
|
235
|
-
`${webhookUrl}${webhookUrl.includes("?") ? "&" : "?"}token=<
|
|
235
|
+
`${webhookUrl}${webhookUrl.includes("?") ? "&" : "?"}token=<WEBHOOK_TOKEN>`;
|
|
236
236
|
const derivedTokenFromQuery = (() => {
|
|
237
237
|
try {
|
|
238
238
|
const parsed = new URL(webhookUrlWithQueryToken);
|
|
@@ -245,7 +245,7 @@ export const Webhooks = ({
|
|
|
245
245
|
selectedWebhook?.authHeaderValue ||
|
|
246
246
|
(derivedTokenFromQuery
|
|
247
247
|
? `Authorization: Bearer ${derivedTokenFromQuery}`
|
|
248
|
-
: "Authorization: Bearer <
|
|
248
|
+
: "Authorization: Bearer <WEBHOOK_TOKEN>");
|
|
249
249
|
const bearerTokenValue = authHeaderValue.startsWith("Authorization: ")
|
|
250
250
|
? authHeaderValue.slice("Authorization: ".length)
|
|
251
251
|
: authHeaderValue;
|
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) {
|
|
@@ -177,7 +177,15 @@ const writeSanitizedOpenclawConfig = ({ fs, openclawDir, varMap }) => {
|
|
|
177
177
|
const replacements = buildSecretReplacements(varMap, process.env);
|
|
178
178
|
for (const [secret, envRef] of replacements) {
|
|
179
179
|
if (secret) {
|
|
180
|
-
|
|
180
|
+
// Only replace exact JSON string values so path substrings are never mutated.
|
|
181
|
+
const secretJson = JSON.stringify(secret);
|
|
182
|
+
content = content.replace(
|
|
183
|
+
new RegExp(
|
|
184
|
+
secretJson.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"),
|
|
185
|
+
"g",
|
|
186
|
+
),
|
|
187
|
+
JSON.stringify(envRef),
|
|
188
|
+
);
|
|
181
189
|
}
|
|
182
190
|
}
|
|
183
191
|
fs.writeFileSync(configPath, content);
|
|
@@ -52,15 +52,13 @@ const normalizeStatusFilter = (rawStatus) => {
|
|
|
52
52
|
|
|
53
53
|
const buildWebhookUrls = ({ baseUrl, name }) => {
|
|
54
54
|
const fullUrl = `${baseUrl}/hooks/${name}`;
|
|
55
|
-
const token = String(
|
|
56
|
-
process.env.OPENCLAW_HOOKS_TOKEN || process.env.WEBHOOK_TOKEN || "",
|
|
57
|
-
).trim();
|
|
55
|
+
const token = String(process.env.WEBHOOK_TOKEN || "").trim();
|
|
58
56
|
const queryStringUrl = token
|
|
59
57
|
? `${fullUrl}?token=${encodeURIComponent(token)}`
|
|
60
|
-
: `${fullUrl}?token=<
|
|
58
|
+
: `${fullUrl}?token=<WEBHOOK_TOKEN>`;
|
|
61
59
|
const authHeaderValue = token
|
|
62
60
|
? `Authorization: Bearer ${token}`
|
|
63
|
-
: "Authorization: Bearer <
|
|
61
|
+
: "Authorization: Bearer <WEBHOOK_TOKEN>";
|
|
64
62
|
return { fullUrl, queryStringUrl, authHeaderValue, hasRuntimeToken: !!token };
|
|
65
63
|
};
|
|
66
64
|
|
package/lib/server/webhooks.js
CHANGED
|
@@ -53,7 +53,7 @@ const ensureHooksRoot = (cfg) => {
|
|
|
53
53
|
if (typeof cfg.hooks.path !== "string" || !cfg.hooks.path.trim())
|
|
54
54
|
cfg.hooks.path = "/hooks";
|
|
55
55
|
if (typeof cfg.hooks.token !== "string" || !cfg.hooks.token.trim()) {
|
|
56
|
-
cfg.hooks.token = "${
|
|
56
|
+
cfg.hooks.token = "${WEBHOOK_TOKEN}";
|
|
57
57
|
}
|
|
58
58
|
if (
|
|
59
59
|
typeof cfg.hooks.defaultSessionKey !== "string" ||
|