@chrysb/alphaclaw 0.9.0-beta.7 → 0.9.1-beta.0
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 +26 -25
- package/lib/cli/git-runtime.js +97 -0
- package/lib/public/css/chat.css +0 -12
- package/lib/public/css/explorer.css +48 -0
- package/lib/public/css/shell.css +149 -0
- package/lib/public/css/tailwind.generated.css +1 -1
- package/lib/public/css/theme.css +265 -0
- package/lib/public/dist/app.bundle.js +2770 -2762
- package/lib/public/js/app.js +26 -14
- package/lib/public/js/components/agents-tab/create-channel-modal.js +259 -59
- package/lib/public/js/components/gateway.js +0 -286
- package/lib/public/js/components/general/index.js +0 -7
- package/lib/public/js/components/icons.js +26 -25
- package/lib/public/js/components/modal-shell.js +1 -1
- package/lib/public/js/components/models-tab/provider-auth-card.js +60 -49
- package/lib/public/js/components/models-tab/use-models.js +74 -9
- package/lib/public/js/components/models.js +52 -37
- package/lib/public/js/components/onboarding/use-welcome-codex.js +34 -24
- package/lib/public/js/components/onboarding/welcome-config.js +76 -10
- package/lib/public/js/components/onboarding/welcome-form-step.js +2 -7
- package/lib/public/js/components/onboarding/welcome-header.js +12 -14
- package/lib/public/js/components/onboarding/welcome-setup-step.js +3 -3
- package/lib/public/js/components/providers.js +53 -42
- package/lib/public/js/components/routes/chat-route.js +2 -9
- package/lib/public/js/components/routes/general-route.js +0 -6
- package/lib/public/js/components/routes/index.js +0 -1
- package/lib/public/js/components/routes/watchdog-route.js +0 -6
- package/lib/public/js/components/sidebar.js +21 -7
- package/lib/public/js/components/theme-toggle.js +113 -0
- package/lib/public/js/components/update-modal.js +174 -51
- package/lib/public/js/components/watchdog-tab/index.js +0 -6
- package/lib/public/js/components/welcome/index.js +0 -2
- package/lib/public/js/components/welcome/use-welcome.js +107 -36
- package/lib/public/js/hooks/use-app-shell-controller.js +16 -33
- package/lib/public/js/lib/api.js +0 -28
- package/lib/public/js/lib/app-navigation.js +0 -2
- package/lib/public/js/lib/channel-provider-availability.js +1 -2
- package/lib/public/js/lib/codex-oauth-window.js +22 -0
- package/lib/public/js/lib/model-catalog.js +31 -0
- package/lib/public/js/lib/storage-keys.js +1 -1
- package/lib/public/login.html +8 -4
- package/lib/public/setup.html +9 -0
- package/lib/scripts/git +110 -16
- package/lib/server/agents/channels.js +1 -4
- package/lib/server/alphaclaw-version.js +590 -132
- package/lib/server/constants.js +5 -0
- package/lib/server/db/webhooks/index.js +48 -8
- package/lib/server/exec-defaults-config.js +163 -0
- package/lib/server/gateway.js +1 -0
- package/lib/server/init/register-server-routes.js +0 -8
- package/lib/server/init/server-lifecycle.js +2 -0
- package/lib/server/model-catalog-cache.js +251 -0
- package/lib/server/onboarding/github.js +83 -2
- package/lib/server/onboarding/index.js +7 -0
- package/lib/server/routes/models.js +14 -23
- package/lib/server/routes/nodes.js +9 -23
- package/lib/server/routes/system.js +3 -16
- package/lib/server/routes/webhooks.js +12 -1
- package/lib/server/startup.js +8 -0
- package/lib/server/watchdog-notify.js +172 -55
- package/lib/server.js +17 -2
- package/lib/setup/core-prompts/AGENTS.md +12 -0
- package/lib/setup/core-prompts/TOOLS.md +12 -0
- package/package.json +2 -2
- package/patches/openclaw+2026.4.9.patch +13 -0
- package/lib/public/js/components/mcp-tab/index.js +0 -237
- package/lib/public/js/components/routes/mcp-route.js +0 -7
- package/lib/server/mcp-bridge.js +0 -158
- package/lib/server/routes/mcp.js +0 -292
- package/patches/openclaw+2026.3.28.patch +0 -13
package/lib/public/js/app.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "wouter-preact";
|
|
10
10
|
import { logout } from "./lib/api.js";
|
|
11
11
|
import { Welcome } from "./components/welcome/index.js";
|
|
12
|
+
import { ThemeToggle } from "./components/theme-toggle.js";
|
|
12
13
|
import { ToastContainer } from "./components/toast.js";
|
|
13
14
|
import { GlobalRestartBanner } from "./components/global-restart-banner.js";
|
|
14
15
|
import { LoadingSpinner } from "./components/loading-spinner.js";
|
|
@@ -21,7 +22,6 @@ import {
|
|
|
21
22
|
DoctorRoute,
|
|
22
23
|
EnvarsRoute,
|
|
23
24
|
GeneralRoute,
|
|
24
|
-
McpRoute,
|
|
25
25
|
ModelsRoute,
|
|
26
26
|
NodesRoute,
|
|
27
27
|
RouteRedirect,
|
|
@@ -105,6 +105,22 @@ const App = () => {
|
|
|
105
105
|
} = useAgentSessions({
|
|
106
106
|
enabled: controllerState.onboarded === true,
|
|
107
107
|
});
|
|
108
|
+
const footerVersion = (() => {
|
|
109
|
+
const openclawVersion = String(
|
|
110
|
+
controllerState.acCurrentOpenclawVersion || "",
|
|
111
|
+
).trim();
|
|
112
|
+
const alphaclawVersion = String(controllerState.acVersion || "").trim();
|
|
113
|
+
if (openclawVersion && alphaclawVersion) {
|
|
114
|
+
return `OpenClaw ${openclawVersion} / AlphaClaw ${alphaclawVersion}`;
|
|
115
|
+
}
|
|
116
|
+
if (openclawVersion) {
|
|
117
|
+
return `OpenClaw ${openclawVersion}`;
|
|
118
|
+
}
|
|
119
|
+
if (alphaclawVersion) {
|
|
120
|
+
return `AlphaClaw ${alphaclawVersion}`;
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
})();
|
|
108
124
|
|
|
109
125
|
useEffect(() => {
|
|
110
126
|
if (!isAgentsRoute) return;
|
|
@@ -161,6 +177,9 @@ const App = () => {
|
|
|
161
177
|
class="min-h-screen flex flex-col items-center pt-12 pb-8 px-4"
|
|
162
178
|
style="position: relative; z-index: 1"
|
|
163
179
|
>
|
|
180
|
+
<div style="position: fixed; top: 16px; right: 16px; z-index: 50;">
|
|
181
|
+
<${ThemeToggle} />
|
|
182
|
+
</div>
|
|
164
183
|
<${Welcome}
|
|
165
184
|
onComplete=${controllerActions.handleOnboardingComplete}
|
|
166
185
|
acVersion=${controllerState.acVersion}
|
|
@@ -198,7 +217,11 @@ const App = () => {
|
|
|
198
217
|
onSelectBrowseFile=${browseActions.navigateToBrowseFile}
|
|
199
218
|
onPreviewBrowseFile=${browseActions.handleBrowsePreviewFile}
|
|
200
219
|
acHasUpdate=${controllerState.acHasUpdate}
|
|
220
|
+
acVersion=${controllerState.acVersion}
|
|
221
|
+
acCurrentOpenclawVersion=${controllerState.acCurrentOpenclawVersion}
|
|
201
222
|
acLatest=${controllerState.acLatest}
|
|
223
|
+
acLatestOpenclawVersion=${controllerState.acLatestOpenclawVersion}
|
|
224
|
+
acUpdateStrategy=${controllerState.acUpdateStrategy}
|
|
202
225
|
acUpdating=${controllerState.acUpdating}
|
|
203
226
|
onAcUpdate=${controllerActions.handleAcUpdate}
|
|
204
227
|
agents=${agentsState.agents}
|
|
@@ -381,9 +404,6 @@ const App = () => {
|
|
|
381
404
|
restartingGateway=${controllerState.restartingGateway}
|
|
382
405
|
onRestartGateway=${controllerActions.handleGatewayRestart}
|
|
383
406
|
restartSignal=${controllerState.gatewayRestartSignal}
|
|
384
|
-
openclawUpdateInProgress=${controllerState.openclawUpdateInProgress}
|
|
385
|
-
onOpenclawVersionActionComplete=${controllerActions.handleOpenclawVersionActionComplete}
|
|
386
|
-
onOpenclawUpdate=${controllerActions.handleOpenclawUpdate}
|
|
387
407
|
onRestartRequired=${controllerActions.setRestartRequired}
|
|
388
408
|
onDismissDoctorWarning=${() =>
|
|
389
409
|
setDoctorWarningDismissedUntilMs(
|
|
@@ -416,9 +436,6 @@ const App = () => {
|
|
|
416
436
|
restartingGateway=${controllerState.restartingGateway}
|
|
417
437
|
onRestartGateway=${controllerActions.handleGatewayRestart}
|
|
418
438
|
restartSignal=${controllerState.gatewayRestartSignal}
|
|
419
|
-
openclawUpdateInProgress=${controllerState.openclawUpdateInProgress}
|
|
420
|
-
onOpenclawVersionActionComplete=${controllerActions.handleOpenclawVersionActionComplete}
|
|
421
|
-
onOpenclawUpdate=${controllerActions.handleOpenclawUpdate}
|
|
422
439
|
/>
|
|
423
440
|
</${Route}>
|
|
424
441
|
<${Route} path="/usage/:sessionId">
|
|
@@ -455,9 +472,6 @@ const App = () => {
|
|
|
455
472
|
onNavigateToBrowseFile=${browseActions.navigateToBrowseFile}
|
|
456
473
|
/>
|
|
457
474
|
</${Route}>
|
|
458
|
-
<${Route} path="/mcp">
|
|
459
|
-
<${McpRoute} />
|
|
460
|
-
</${Route}>
|
|
461
475
|
<${Route}>
|
|
462
476
|
<${RouteRedirect} to="/general" />
|
|
463
477
|
</${Route}>
|
|
@@ -472,10 +486,8 @@ const App = () => {
|
|
|
472
486
|
|
|
473
487
|
<div class="app-statusbar">
|
|
474
488
|
<div class="statusbar-left">
|
|
475
|
-
${
|
|
476
|
-
? html`<span style="color: var(--text-muted)"
|
|
477
|
-
>v${controllerState.acVersion}</span
|
|
478
|
-
>`
|
|
489
|
+
${footerVersion
|
|
490
|
+
? html`<span style="color: var(--text-muted)">${footerVersion}</span>`
|
|
479
491
|
: null}
|
|
480
492
|
</div>
|
|
481
493
|
<div class="statusbar-right">
|
|
@@ -2,12 +2,15 @@ import { h } from "preact";
|
|
|
2
2
|
import { useEffect, useMemo, useState } from "preact/hooks";
|
|
3
3
|
import htm from "htm";
|
|
4
4
|
import { ActionButton } from "../action-button.js";
|
|
5
|
-
import { CloseIcon } from "../icons.js";
|
|
5
|
+
import { CloseIcon, FileCopyLineIcon } from "../icons.js";
|
|
6
6
|
import { ModalShell } from "../modal-shell.js";
|
|
7
7
|
import { PageHeader } from "../page-header.js";
|
|
8
8
|
import { SecretInput } from "../secret-input.js";
|
|
9
9
|
import { fetchChannelAccountToken } from "../../lib/api.js";
|
|
10
|
+
import { copyTextToClipboard } from "../../lib/clipboard.js";
|
|
11
|
+
import { isSingleAccountChannelProvider } from "../../lib/channel-provider-availability.js";
|
|
10
12
|
import { ALL_CHANNELS, getChannelMeta } from "../channels.js";
|
|
13
|
+
import { showToast } from "../toast.js";
|
|
11
14
|
|
|
12
15
|
const html = htm.bind(h);
|
|
13
16
|
|
|
@@ -25,15 +28,33 @@ const kSlackBotScopes = [
|
|
|
25
28
|
"channels:history",
|
|
26
29
|
"channels:read",
|
|
27
30
|
"chat:write",
|
|
31
|
+
"commands",
|
|
32
|
+
"emoji:read",
|
|
33
|
+
"files:read",
|
|
34
|
+
"files:write",
|
|
35
|
+
"groups:read",
|
|
28
36
|
"groups:history",
|
|
29
37
|
"im:history",
|
|
30
38
|
"im:read",
|
|
31
39
|
"im:write",
|
|
32
40
|
"mpim:history",
|
|
41
|
+
"mpim:read",
|
|
42
|
+
"mpim:write",
|
|
43
|
+
"pins:read",
|
|
44
|
+
"pins:write",
|
|
33
45
|
"reactions:read",
|
|
34
46
|
"reactions:write",
|
|
35
47
|
"users:read",
|
|
36
48
|
];
|
|
49
|
+
const kSlackBotEvents = [
|
|
50
|
+
"app_mention",
|
|
51
|
+
"message.channels",
|
|
52
|
+
"message.groups",
|
|
53
|
+
"message.im",
|
|
54
|
+
"message.mpim",
|
|
55
|
+
"reaction_added",
|
|
56
|
+
"reaction_removed",
|
|
57
|
+
];
|
|
37
58
|
const kSlackInstructionsLink = "https://docs.openclaw.ai/channels/slack";
|
|
38
59
|
|
|
39
60
|
const slugifyChannelAccountId = (value) =>
|
|
@@ -50,7 +71,63 @@ const deriveChannelEnvKey = ({ provider, accountId }) => {
|
|
|
50
71
|
if (!normalizedAccountId || normalizedAccountId === "default") return baseKey;
|
|
51
72
|
return `${baseKey}_${normalizedAccountId.replace(/-/g, "_").toUpperCase()}`;
|
|
52
73
|
};
|
|
74
|
+
const deriveChannelExtraEnvKey = ({ provider, accountId, index = 0 }) => {
|
|
75
|
+
const baseKeys = [kChannelExtraEnvKeys[String(provider || "").trim()]].filter(
|
|
76
|
+
Boolean,
|
|
77
|
+
);
|
|
78
|
+
const baseKey = String(baseKeys[index] || "").trim();
|
|
79
|
+
const normalizedAccountId = String(accountId || "").trim();
|
|
80
|
+
if (!baseKey) return "";
|
|
81
|
+
if (!normalizedAccountId || normalizedAccountId === "default") return baseKey;
|
|
82
|
+
return `${baseKey}_${normalizedAccountId.replace(/-/g, "_").toUpperCase()}`;
|
|
83
|
+
};
|
|
53
84
|
const isMaskedTokenValue = (value) => /^\*+$/.test(String(value || "").trim());
|
|
85
|
+
const buildSlackManifest = (appName = "AlphaClaw") =>
|
|
86
|
+
JSON.stringify(
|
|
87
|
+
{
|
|
88
|
+
_metadata: {
|
|
89
|
+
major_version: 1,
|
|
90
|
+
},
|
|
91
|
+
display_information: {
|
|
92
|
+
name: String(appName || "").trim() || "AlphaClaw",
|
|
93
|
+
description: "Slack connector for AlphaClaw",
|
|
94
|
+
},
|
|
95
|
+
features: {
|
|
96
|
+
bot_user: {
|
|
97
|
+
display_name: String(appName || "").trim() || "AlphaClaw",
|
|
98
|
+
always_online: false,
|
|
99
|
+
},
|
|
100
|
+
app_home: {
|
|
101
|
+
messages_tab_enabled: true,
|
|
102
|
+
messages_tab_read_only_enabled: false,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
oauth_config: {
|
|
106
|
+
scopes: {
|
|
107
|
+
bot: kSlackBotScopes,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
settings: {
|
|
111
|
+
event_subscriptions: {
|
|
112
|
+
bot_events: kSlackBotEvents,
|
|
113
|
+
},
|
|
114
|
+
org_deploy_enabled: false,
|
|
115
|
+
socket_mode_enabled: true,
|
|
116
|
+
is_hosted: false,
|
|
117
|
+
token_rotation_enabled: false,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
null,
|
|
121
|
+
2,
|
|
122
|
+
);
|
|
123
|
+
const copyAndToast = async (value, label = "text") => {
|
|
124
|
+
const copied = await copyTextToClipboard(value);
|
|
125
|
+
if (copied) {
|
|
126
|
+
showToast("Copied to clipboard", "success");
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
showToast(`Could not copy ${label}`, "error");
|
|
130
|
+
};
|
|
54
131
|
|
|
55
132
|
export const CreateChannelModal = ({
|
|
56
133
|
visible = false,
|
|
@@ -152,9 +229,7 @@ export const CreateChannelModal = ({
|
|
|
152
229
|
}
|
|
153
230
|
setName(providerLabel);
|
|
154
231
|
}, [provider, providerHasAccounts, nameEditedManually, isEditMode]);
|
|
155
|
-
const isSingleAccountProvider =
|
|
156
|
-
String(provider || "").trim() === "discord" ||
|
|
157
|
-
String(provider || "").trim() === "slack";
|
|
232
|
+
const isSingleAccountProvider = isSingleAccountChannelProvider(provider);
|
|
158
233
|
const needsAppToken = String(provider || "").trim() === "slack";
|
|
159
234
|
|
|
160
235
|
const accountId = useMemo(() => {
|
|
@@ -170,6 +245,24 @@ export const CreateChannelModal = ({
|
|
|
170
245
|
() => deriveChannelEnvKey({ provider, accountId }),
|
|
171
246
|
[provider, accountId],
|
|
172
247
|
);
|
|
248
|
+
const extraEnvKey = useMemo(
|
|
249
|
+
() =>
|
|
250
|
+
deriveChannelExtraEnvKey({
|
|
251
|
+
provider,
|
|
252
|
+
accountId,
|
|
253
|
+
}),
|
|
254
|
+
[provider, accountId],
|
|
255
|
+
);
|
|
256
|
+
const slackManifestName = useMemo(() => {
|
|
257
|
+
const normalizedName = String(name || "").trim();
|
|
258
|
+
if (!normalizedName) return "AlphaClaw";
|
|
259
|
+
if (normalizedName.toLowerCase() === "slack") return "AlphaClaw";
|
|
260
|
+
return normalizedName;
|
|
261
|
+
}, [name]);
|
|
262
|
+
const slackManifest = useMemo(
|
|
263
|
+
() => buildSlackManifest(slackManifestName),
|
|
264
|
+
[slackManifestName],
|
|
265
|
+
);
|
|
173
266
|
|
|
174
267
|
const accountExists = useMemo(
|
|
175
268
|
() =>
|
|
@@ -269,7 +362,7 @@ export const CreateChannelModal = ({
|
|
|
269
362
|
<${ModalShell}
|
|
270
363
|
visible=${visible}
|
|
271
364
|
onClose=${onClose}
|
|
272
|
-
panelClassName="bg-modal border border-border rounded-xl p-6 max-w-lg w-full space-y-4"
|
|
365
|
+
panelClassName="bg-modal border border-border rounded-xl p-6 max-w-lg w-full max-h-[calc(100vh-2rem)] overflow-y-auto space-y-4"
|
|
273
366
|
>
|
|
274
367
|
<${PageHeader}
|
|
275
368
|
title=${
|
|
@@ -360,7 +453,7 @@ export const CreateChannelModal = ({
|
|
|
360
453
|
<p class="text-xs text-fg-muted">
|
|
361
454
|
Saved behind the scenes as
|
|
362
455
|
<code class="font-mono text-fg-muted ml-1">
|
|
363
|
-
${kChannelExtraEnvKeys.slack}
|
|
456
|
+
${extraEnvKey || kChannelExtraEnvKeys.slack}
|
|
364
457
|
</code>
|
|
365
458
|
.
|
|
366
459
|
</p>
|
|
@@ -371,60 +464,167 @@ export const CreateChannelModal = ({
|
|
|
371
464
|
${
|
|
372
465
|
needsAppToken
|
|
373
466
|
? html`
|
|
374
|
-
<
|
|
375
|
-
<
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
</
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
</
|
|
402
|
-
<
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
467
|
+
<div class="space-y-2">
|
|
468
|
+
<details
|
|
469
|
+
class="rounded-lg border border-border bg-field px-3 py-2.5"
|
|
470
|
+
>
|
|
471
|
+
<summary
|
|
472
|
+
class="cursor-pointer text-xs text-body hover:text-body"
|
|
473
|
+
>
|
|
474
|
+
<span class="inline-block ml-1">
|
|
475
|
+
Create app from manifest (recommended)
|
|
476
|
+
</span>
|
|
477
|
+
</summary>
|
|
478
|
+
<div class="mt-2 space-y-2 text-xs text-fg-muted">
|
|
479
|
+
<div class="flex items-center justify-between gap-3 pt-1">
|
|
480
|
+
<div class="space-y-0.5">
|
|
481
|
+
<p class="text-[12px] text-fg-muted">
|
|
482
|
+
${slackManifestName} App Manifest
|
|
483
|
+
</p>
|
|
484
|
+
</div>
|
|
485
|
+
<button
|
|
486
|
+
type="button"
|
|
487
|
+
onclick=${() =>
|
|
488
|
+
copyAndToast(slackManifest, "Slack manifest")}
|
|
489
|
+
class="text-xs px-2 py-1 rounded-lg ac-btn-cyan inline-flex items-center gap-1.5 shrink-0"
|
|
490
|
+
>
|
|
491
|
+
<${FileCopyLineIcon} className="w-3.5 h-3.5" />
|
|
492
|
+
Copy
|
|
493
|
+
</button>
|
|
494
|
+
</div>
|
|
495
|
+
<pre
|
|
496
|
+
class="max-h-72 overflow-auto rounded-lg border border-border bg-field p-3 text-[11px] leading-5 whitespace-pre-wrap break-all font-mono text-body"
|
|
497
|
+
>
|
|
498
|
+
${slackManifest}</pre
|
|
499
|
+
>
|
|
500
|
+
<ol
|
|
501
|
+
class="list-decimal list-inside space-y-1.5 text-[11px] text-fg-muted"
|
|
502
|
+
>
|
|
503
|
+
<li>
|
|
504
|
+
In Slack, click ${" "}
|
|
505
|
+
<span class="text-body"
|
|
506
|
+
>Create app from manifest</span
|
|
507
|
+
>
|
|
508
|
+
${" "} and paste this manifest.
|
|
509
|
+
</li>
|
|
510
|
+
<li>
|
|
511
|
+
Open ${" "}
|
|
512
|
+
<span class="text-body">Basic Information</span>
|
|
513
|
+
${" "} and create an ${" "}
|
|
514
|
+
<span class="text-body">App-Level Token</span>
|
|
515
|
+
${" "} with
|
|
516
|
+
<code class="font-mono text-fg-muted ml-1"
|
|
517
|
+
>connections:write</code
|
|
518
|
+
>.
|
|
519
|
+
</li>
|
|
520
|
+
<li>
|
|
521
|
+
Open ${" "}
|
|
522
|
+
<span class="text-body">OAuth & Permissions</span>
|
|
523
|
+
${" "} and use ${" "}
|
|
524
|
+
<span class="text-body">Install to Workspace</span>
|
|
525
|
+
${" "} or ${" "}
|
|
526
|
+
<span class="text-body">Reinstall to Workspace</span>
|
|
527
|
+
${" "} so Slack issues a bot token.
|
|
528
|
+
</li>
|
|
529
|
+
<li>
|
|
530
|
+
In ${" "}
|
|
531
|
+
<span class="text-body">OAuth & Permissions</span>
|
|
532
|
+
${" "} copy the ${" "}
|
|
533
|
+
<span class="text-body">Bot User OAuth Token</span>
|
|
534
|
+
${" "} (
|
|
535
|
+
<code class="font-mono text-fg-muted">xoxb-...</code>
|
|
536
|
+
).
|
|
537
|
+
</li>
|
|
538
|
+
<li>
|
|
539
|
+
Paste the generated ${" "}
|
|
540
|
+
<code class="font-mono text-fg-muted">xoxb-...</code>
|
|
541
|
+
${" "} and ${" "}
|
|
542
|
+
<code class="font-mono text-fg-muted">xapp-...</code>
|
|
543
|
+
${" "} tokens here.
|
|
544
|
+
</li>
|
|
545
|
+
</ol>
|
|
546
|
+
</div>
|
|
547
|
+
</details>
|
|
548
|
+
<details
|
|
549
|
+
class="rounded-lg border border-border bg-field px-3 py-2.5"
|
|
550
|
+
>
|
|
551
|
+
<summary
|
|
552
|
+
class="cursor-pointer text-xs text-body hover:text-body"
|
|
423
553
|
>
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
554
|
+
<span class="inline-block ml-1">
|
|
555
|
+
Manual setup instructions
|
|
556
|
+
</span>
|
|
557
|
+
</summary>
|
|
558
|
+
<div class="mt-2 space-y-2 text-xs text-fg-muted">
|
|
559
|
+
<p>
|
|
560
|
+
Use this if you want to configure the Slack app by hand
|
|
561
|
+
instead of importing a manifest.
|
|
562
|
+
</p>
|
|
563
|
+
<ol class="list-decimal list-inside space-y-1.5">
|
|
564
|
+
<li>
|
|
565
|
+
In Slack app settings, turn on ${" "}
|
|
566
|
+
<span class="text-body">Socket Mode</span>.
|
|
567
|
+
</li>
|
|
568
|
+
<li>
|
|
569
|
+
In ${" "}
|
|
570
|
+
<span class="text-body">App Home</span>, enable
|
|
571
|
+
<code class="font-mono text-fg-muted ml-1">
|
|
572
|
+
Allow users to send Slash commands and messages from
|
|
573
|
+
the messages tab </code
|
|
574
|
+
>.
|
|
575
|
+
</li>
|
|
576
|
+
<li>
|
|
577
|
+
In ${" "}
|
|
578
|
+
<span class="text-body">Event Subscriptions</span>,
|
|
579
|
+
toggle on
|
|
580
|
+
<code class="font-mono text-fg-muted ml-1"
|
|
581
|
+
>Subscribe to bot events</code
|
|
582
|
+
>
|
|
583
|
+
${" "} and add
|
|
584
|
+
<code class="font-mono text-fg-muted ml-1"
|
|
585
|
+
>message.im</code
|
|
586
|
+
>.
|
|
587
|
+
</li>
|
|
588
|
+
<li>
|
|
589
|
+
In ${" "}
|
|
590
|
+
<span class="text-body">OAuth & Permissions</span>,
|
|
591
|
+
add the bot scopes:
|
|
592
|
+
<code class="font-mono text-fg-muted ml-1">
|
|
593
|
+
${kSlackBotScopes.join(", ")}
|
|
594
|
+
</code>
|
|
595
|
+
</li>
|
|
596
|
+
<li>
|
|
597
|
+
In ${" "}
|
|
598
|
+
<span class="text-body">Basic Information</span>,
|
|
599
|
+
create an App Token (<code
|
|
600
|
+
class="font-mono text-fg-muted"
|
|
601
|
+
>xapp-...</code
|
|
602
|
+
>) with
|
|
603
|
+
<code class="font-mono text-fg-muted ml-1"
|
|
604
|
+
>connections:write</code
|
|
605
|
+
>.
|
|
606
|
+
</li>
|
|
607
|
+
<li>
|
|
608
|
+
Back in ${" "}
|
|
609
|
+
<span class="text-body">OAuth & Permissions</span>,
|
|
610
|
+
install or reinstall the app, then copy the ${" "}
|
|
611
|
+
<span class="text-body">Bot User OAuth Token</span>
|
|
612
|
+
${" "} (
|
|
613
|
+
<code class="font-mono text-fg-muted">xoxb-...</code>
|
|
614
|
+
).
|
|
615
|
+
</li>
|
|
616
|
+
</ol>
|
|
617
|
+
<a
|
|
618
|
+
href=${kSlackInstructionsLink}
|
|
619
|
+
target="_blank"
|
|
620
|
+
class="hover:underline"
|
|
621
|
+
style="color: var(--accent-link)"
|
|
622
|
+
>
|
|
623
|
+
Open full Slack setup guide
|
|
624
|
+
</a>
|
|
625
|
+
</div>
|
|
626
|
+
</details>
|
|
627
|
+
</div>
|
|
428
628
|
`
|
|
429
629
|
: null
|
|
430
630
|
}
|