@@ -3,9 +3,9 @@
|
||||
"section": 1,
|
||||
"title": "discord-bot",
|
||||
"synopsis": [
|
||||
"discord-bot [--env PATH] [--token TOKEN] [--guild ID] [--check] [--debug] [--message-content] [--login-timeout MS]"
|
||||
"discord-bot [--env PATH] [--token TOKEN] [--guild ID] [--check] [--debug] [--message-content] [--login-timeout MS] [--no-user-install]"
|
||||
],
|
||||
"description": "Bare OS Discord bot via ctx.bare.discordJS. Commands run as the unlocked session user (not guest). /r requires cmd and is a non-interactive shell (cwd, history, autocomplete). /upload attaches a file and wget-saves it into the /r cwd or a given path. /hdms manages extra Hyperdrives (list, create, add, invite, pair, health) via ctx.runHdms. /holesail manages persisted Holesail tunnels and the bare-holesail unit (list, add, edit, start/stop, enable/disable, service, url) via ctx.bareOsRunHolesailCli; show never prints seed material. /plugins loads JSON or JS from ~/.discord/plugins (see developer-guide ch.21). Also /settings, /files, /panel, /edit, /create, /bare, /sys, /svc, /fs, /net, /man, /say, /journal, /ping. Embeds paginate when large and expire after 2 minutes idle. Token from --token, DISCORD_TOKEN, or ~/.discord/.env. DISCORD_ID_WHITELIST restricts who may use slash commands and message components. The initd unit bare-os-discord is listed by systemctl only when ~/.discord/.env exists.",
|
||||
"description": "Bare OS Discord bot via ctx.bare.discordJS. Commands run as the unlocked session user (not guest). /r requires cmd and is a non-interactive shell (cwd, history, autocomplete). /upload attaches a file and wget-saves it into the /r cwd or a given path. /hdms manages extra Hyperdrives (list, create, add, invite, pair, health) via ctx.runHdms. /holesail manages persisted Holesail tunnels and the bare-holesail unit (list, add, edit, start/stop, enable/disable, service, url) via ctx.bareOsRunHolesailCli; show never prints seed material. /agent runs the guest AI agent when ~/.agent/config.json is ready (QVAC + host bridge, or REST + API key): ask, status, config, reset, stop; history is shared with /bin/agent and API keys are never shown. /plugins loads JSON or JS from ~/.discord/plugins (see developer-guide ch.21). Also /settings, /files, /panel, /edit, /create, /bare, /sys, /svc, /fs, /net, /man, /say, /journal, /ping. Embeds paginate when large and expire after 2 minutes idle. Token from --token, DISCORD_TOKEN, or ~/.discord/.env. User-installable (Add App to your Discord profile) is on by default so slash commands work in DMs and any server; DISCORD_ID_WHITELIST is always enforced on those surfaces (empty list denies user-install / DM use). The initd unit bare-os-discord is listed by systemctl only when ~/.discord/.env exists.",
|
||||
"options": [
|
||||
{
|
||||
"flag": "--env PATH",
|
||||
@@ -34,6 +34,10 @@
|
||||
{
|
||||
"flag": "--login-timeout MS",
|
||||
"meaning": "Fail login if the gateway is not ready after MS milliseconds (default 45000)."
|
||||
},
|
||||
{
|
||||
"flag": "--no-user-install",
|
||||
"meaning": "Guild-only bot. Do not register user-install (profile app) commands. Same as DISCORD_USER_INSTALL=0."
|
||||
}
|
||||
],
|
||||
"keywords": ["discord", "bot", "ping", "pong", "ctx.bare"],
|
||||
@@ -42,7 +46,8 @@
|
||||
"DISCORD_ENV_FILE / BARE_OS_DISCORD_ENV_FILE — path to a .env file. On the host this may be a host filesystem path (booter reads it). In the guest it is a VFS path. Preferred guest path: ~/.discord/.env.",
|
||||
"BARE_OS_DISCORD_INITD — set 0 / false to never register the bare-os-discord systemctl unit, even when ~/.discord/.env exists.",
|
||||
"DISCORD_GUILD_ID — optional guild for slash-command registration.",
|
||||
"DISCORD_ID_WHITELIST — comma-separated Discord user ids allowed to use the bot (slash, autocomplete, buttons, selects, modals, and channel ping). Unset or empty allows everyone to start commands; message components still belong to the operator who posted them. A user not on a non-empty list is denied (ephemeral reply).",
|
||||
"DISCORD_ID_WHITELIST — comma-separated Discord user ids allowed to use the bot (slash, autocomplete, buttons, selects, modals, and channel ping). Unset or empty still allows guild-installed commands in a server, but user-install / DM / private-channel use is always denied. A user not on a non-empty list is denied (ephemeral reply) in every install context.",
|
||||
"DISCORD_USER_INSTALL / BARE_OS_DISCORD_USER_INSTALL — user-installable profile app (default on). Set 0 / false / off for a guild-only bot.",
|
||||
"DISCORD_MESSAGE_CONTENT / BARE_OS_DISCORD_MESSAGE_CONTENT — set 1 to request Message Content Intent (same as --message-content).",
|
||||
"DISCORD_DEBUG / BARE_OS_DISCORD_DEBUG — set 1 to print discord.js debug lines.",
|
||||
"DISCORD_LOGIN_TIMEOUT_MS — login deadline in milliseconds (default 45000).",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"synopsis": [
|
||||
"init-discord [--token TOKEN] [--guild ID] [--whitelist ID,ID] [--yes] [--force] [--plugin-only]"
|
||||
],
|
||||
"description": "Set up the stock Discord bot on this session. Creates ~/.discord and ~/.discord/plugins, writes ~/.discord/.env (DISCORD_TOKEN, optional DISCORD_GUILD_ID and DISCORD_ID_WHITELIST), and installs the hello-world plugin ~/.discord/plugins/hello.json (/hello). Interactive by default: prompts for token, guild id, and whitelist. Never prints the full token. After setup run discord-bot --check and start bare-os-discord.",
|
||||
"description": "Set up the stock Discord bot on this session. Creates ~/.discord and ~/.discord/plugins, writes ~/.discord/.env (DISCORD_TOKEN, optional DISCORD_GUILD_ID and DISCORD_ID_WHITELIST), and installs the hello-world plugin ~/.discord/plugins/hello.json (/hello). Interactive by default: prompts for token, guild id, and whitelist. Never prints the full token. After setup run discord-bot --check, start bare-os-discord, and open the logged profile-install URL. DISCORD_ID_WHITELIST is required for user-install / DM commands.",
|
||||
"options": [
|
||||
{
|
||||
"flag": "--token TOKEN",
|
||||
@@ -17,7 +17,7 @@
|
||||
},
|
||||
{
|
||||
"flag": "--whitelist ID,ID",
|
||||
"meaning": "Comma-separated Discord user ids allowed to use the bot."
|
||||
"meaning": "Comma-separated Discord user ids allowed to use the bot. Required for user-install / DM commands."
|
||||
},
|
||||
{
|
||||
"flag": "--yes",
|
||||
|
||||
@@ -160,15 +160,19 @@ function discordUsage(argv0) {
|
||||
(argv0 || 'discord-bot') +
|
||||
' [--env PATH] [--token TOKEN] [--guild ID] [--check]\n' +
|
||||
' [--debug] [--message-content] [--login-timeout MS]\n' +
|
||||
' [--no-user-install]\n' +
|
||||
'Ping-pong bot via ctx.bare.discordJS.\n' +
|
||||
'Token from --token, DISCORD_TOKEN, or a .env file (--env, DISCORD_ENV_FILE,\n' +
|
||||
'host DISCORD_ENV_FILE, ~/.discord/.env, ~/.discord.env).\n' +
|
||||
'Ctrl+C stops the foreground bot. Initd unit bare-os-discord appears in\n' +
|
||||
'systemctl only when ~/.discord/.env exists with DISCORD_TOKEN=.\n' +
|
||||
'Slash commands: /panel /files /edit /create /upload /hdms /holesail /bare /sys /svc /fs /net /man /say /r /journal /ping.\n' +
|
||||
'Slash commands: /panel /files /edit /create /upload /hdms /holesail /agent /bare /sys /svc /fs /net /man /say /r /journal /ping.\n' +
|
||||
'Commands run as the unlocked session user. Options use Discord autocomplete.\n' +
|
||||
'Channel "ping" still replies pong when Message Content Intent is enabled.\n' +
|
||||
'DISCORD_ID_WHITELIST=id,id in .env restricts the bot to those Discord user ids.'
|
||||
'User-installable (profile app) is on by default so operators can use slash\n' +
|
||||
'commands in DMs and any server. DISCORD_ID_WHITELIST is always enforced on\n' +
|
||||
'those surfaces (empty list denies user-install / DM use). Guild-only mode:\n' +
|
||||
'--no-user-install or DISCORD_USER_INSTALL=0.'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -227,7 +231,11 @@ async function discordLoadToken(ctx, argv) {
|
||||
function discordApplyDotEnvExtras(ctx, parsed) {
|
||||
if (!parsed || !ctx) return
|
||||
if (!ctx.env) ctx.env = {}
|
||||
const extras = ['DISCORD_GUILD_ID', 'DISCORD_ID_WHITELIST']
|
||||
const extras = [
|
||||
'DISCORD_GUILD_ID',
|
||||
'DISCORD_ID_WHITELIST',
|
||||
'DISCORD_USER_INSTALL'
|
||||
]
|
||||
for (let i = 0; i < extras.length; i++) {
|
||||
const k = extras[i]
|
||||
const v = parsed[k]
|
||||
@@ -336,6 +344,14 @@ async function run(ctx, argv) {
|
||||
discordArgValue(argv, ['--guild', '--guild-id']) ||
|
||||
(ctx.env && ctx.env.DISCORD_GUILD_ID) ||
|
||||
''
|
||||
if (discordHasFlag(argv, ['--no-user-install', '--guild-only'])) {
|
||||
if (!ctx.env) ctx.env = {}
|
||||
ctx.env.DISCORD_USER_INSTALL = '0'
|
||||
}
|
||||
const userInstallOn =
|
||||
typeof discordUserInstallEnabled === 'function'
|
||||
? discordUserInstallEnabled(ctx)
|
||||
: true
|
||||
|
||||
const Client = dj.Client
|
||||
const GatewayIntentBits = dj.GatewayIntentBits
|
||||
@@ -376,17 +392,55 @@ async function run(ctx, argv) {
|
||||
]
|
||||
)
|
||||
|
||||
async function discordRegisterSlashBody(body) {
|
||||
const rest = new REST().setToken(loaded.token)
|
||||
const appId = client.user && client.user.id
|
||||
if (!appId) return
|
||||
if (userInstallOn && typeof discordEnableUserInstallApp === 'function') {
|
||||
try {
|
||||
await discordEnableUserInstallApp(rest, Routes)
|
||||
} catch (err) {
|
||||
ctx.console.error(
|
||||
'discord-bot: user-install app config failed: ' +
|
||||
((err && err.message) || String(err)) +
|
||||
' (enable User Install under Developer Portal → Installation)'
|
||||
)
|
||||
}
|
||||
}
|
||||
if (typeof discordPutSlashCommands === 'function') {
|
||||
const put = await discordPutSlashCommands(rest, Routes, appId, body, {
|
||||
guildId: guildId,
|
||||
userInstall: userInstallOn
|
||||
})
|
||||
if (put.global) {
|
||||
ctx.console.log(
|
||||
'Registered ' +
|
||||
body.length +
|
||||
' global slash commands' +
|
||||
(userInstallOn ? ' (user-install + guild)' : '') +
|
||||
(guildId ? '' : ' (may take up to ~1 hour)')
|
||||
)
|
||||
}
|
||||
if (put.guild) {
|
||||
ctx.console.log(
|
||||
'Registered ' + body.length + ' slash commands for guild ' + guildId
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (guildId) {
|
||||
await rest.put(Routes.applicationGuildCommands(appId, guildId), {
|
||||
body: body
|
||||
})
|
||||
} else {
|
||||
await rest.put(Routes.applicationCommands(appId), { body: body })
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof discordPluginsSetRegistrar === 'function') {
|
||||
discordPluginsSetRegistrar(async function () {
|
||||
const body = await Promise.resolve(discordBuildSlashCommands(dj, ctx))
|
||||
const rest = new REST().setToken(loaded.token)
|
||||
const appId = client.user && client.user.id
|
||||
if (!appId) return
|
||||
if (guildId) {
|
||||
await rest.put(Routes.applicationGuildCommands(appId, guildId), { body: body })
|
||||
} else {
|
||||
await rest.put(Routes.applicationCommands(appId), { body: body })
|
||||
}
|
||||
await discordRegisterSlashBody(body)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -394,24 +448,12 @@ async function run(ctx, argv) {
|
||||
ctx.console.log('Logged in as ' + readyClient.user.tag)
|
||||
if (typeof REST !== 'function' || !Routes) return
|
||||
try {
|
||||
const rest = new REST().setToken(loaded.token)
|
||||
const appId = readyClient.user.id
|
||||
if (guildId) {
|
||||
await rest.put(Routes.applicationGuildCommands(appId, guildId), {
|
||||
body: slashBody
|
||||
})
|
||||
ctx.console.log(
|
||||
'Registered ' + slashBody.length + ' slash commands for guild ' + guildId
|
||||
)
|
||||
} else {
|
||||
await rest.put(Routes.applicationCommands(appId), {
|
||||
body: slashBody
|
||||
})
|
||||
ctx.console.log(
|
||||
'Registered ' +
|
||||
slashBody.length +
|
||||
' global slash commands (may take up to ~1 hour). Set DISCORD_GUILD_ID or --guild for instant updates.'
|
||||
)
|
||||
await discordRegisterSlashBody(slashBody)
|
||||
if (userInstallOn && typeof discordUserInstallAuthorizeUrl === 'function') {
|
||||
const url = discordUserInstallAuthorizeUrl(readyClient.user.id)
|
||||
if (url) {
|
||||
ctx.console.log('discord-bot: add to your Discord profile: ' + url)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
ctx.console.error(
|
||||
@@ -431,7 +473,10 @@ async function run(ctx, argv) {
|
||||
if (interaction.commandName !== 'ping') return
|
||||
const uid =
|
||||
interaction.user && interaction.user.id ? interaction.user.id : ''
|
||||
if (typeof discordUserAllowed === 'function' && !discordUserAllowed(ctx, uid)) {
|
||||
if (
|
||||
typeof discordUserAllowed === 'function' &&
|
||||
!discordUserAllowed(ctx, uid, interaction)
|
||||
) {
|
||||
try {
|
||||
await interaction.reply({
|
||||
content:
|
||||
@@ -600,6 +645,10 @@ async function run(ctx, argv) {
|
||||
ctx.console.log(
|
||||
'discord-bot: DISCORD_ID_WHITELIST active (' + wlN + ' user id(s))'
|
||||
)
|
||||
} else if (userInstallOn) {
|
||||
ctx.console.log(
|
||||
'discord-bot: user-install is on and DISCORD_ID_WHITELIST is empty — user-install / DM commands are denied until you add your Discord user id'
|
||||
)
|
||||
}
|
||||
}
|
||||
if (!wantsMessageContent) {
|
||||
|
||||
@@ -171,7 +171,7 @@ async function run(ctx, argv) {
|
||||
)
|
||||
white = await initDiscordAsk(
|
||||
ctx,
|
||||
'DISCORD_ID_WHITELIST (your user id, comma-separated)',
|
||||
'DISCORD_ID_WHITELIST (required for profile-install / DMs)',
|
||||
white || prevWhite
|
||||
)
|
||||
} else if (!token) {
|
||||
@@ -221,6 +221,8 @@ async function run(ctx, argv) {
|
||||
ctx.console.log(' discord-bot --check --env ~/.discord/.env')
|
||||
ctx.console.log(' discord-bot --env ~/.discord/.env')
|
||||
ctx.console.log(' systemctl daemon-reload && systemctl start bare-os-discord')
|
||||
ctx.console.log(' Open the logged "add to your Discord profile" URL (Add App → User Install).')
|
||||
ctx.console.log(' DISCORD_ID_WHITELIST is enforced on profile-install / DM commands.')
|
||||
ctx.console.log(' /plugins reload (after the bot is online)')
|
||||
ctx.exitCode = 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user