Updates
Release rolling / release (push) Successful in 14m50s

This commit is contained in:
2026-08-18 12:40:52 -04:00
parent 3fe8dbfa0b
commit e7b00df454
21 changed files with 4692 additions and 181 deletions
@@ -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",
+79 -30
View File
@@ -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
}