Updates
Release rolling / release (push) Successful in 10m20s

This commit is contained in:
2026-08-18 20:01:31 -04:00
parent 4eb767d65e
commit d3aa66b0cc
32 changed files with 1671 additions and 190 deletions
@@ -332,6 +332,7 @@ test('discord command catalog builds Bare OS slash commands', async (t) => {
t.ok(names.indexOf('hdms') >= 0)
t.ok(names.indexOf('holesail') >= 0)
t.ok(names.indexOf('agent') >= 0)
t.ok(names.indexOf('status') >= 0, 'slash /status exists')
t.ok(body.every((c) => Array.isArray(c.integration_types) && c.integration_types.indexOf(1) >= 0))
t.ok(body.every((c) => Array.isArray(c.contexts) && c.contexts.length === 3))
const guildOnly = await cmds.buildSlashCommands(
@@ -1796,7 +1797,7 @@ test('Discord /agent is gated on config and runs the guest agent', async (t) =>
lines.push({ line: String(line), timeoutMs: opts && opts.timeoutMs })
t.is(ctx.env.BARE_OS_AGENT_DISCORD, '1', 'discord markdown mode')
t.absent(ctx.env.BARE_OS_AGENT_PLAIN, 'does not force TTY-plain replies')
ctx.console.log('→ read_file\n**hello from** `' + String(line) + '`')
ctx.console.log('→ read_file\n**hello** from `' + String(line) + '`')
ctx.exitCode = 0
},
bareOsQvacAvailable: () => false
@@ -2004,16 +2005,22 @@ test('Discord /agent is gated on config and runs the guest agent', async (t) =>
)
t.ok(lines.some((l) => l.timeoutMs > 60000), 'agent timeout longer than /r')
t.ok(
views.some((v) => /hello from/.test(JSON.stringify(v || {}))),
views.some((v) => /hello/.test(JSON.stringify(v || {}))),
'agent stdout captured into Discord'
)
const finalAsk = [...views].reverse().find((v) => {
const e = v && v.embeds && v.embeds[0]
return e && e.description && e.title !== 'Agent · working'
})
const finalDesc = (finalAsk && finalAsk.embeds[0].description) || ''
t.ok(/\*\*hello\*\*/.test(finalDesc), 'final agent reply includes Discord markdown')
t.ok(!/```[\s\S]*\*\*hello\*\*/.test(finalDesc), 'final reply is not wrapped in a code fence')
t.ok(!/\*\*qvac\*\*/i.test(finalDesc), 'no backend preamble on final reply')
t.ok(!/_list \/bin_/.test(finalDesc), 'no italic prompt echo on final reply')
t.ok(!/Loading model/i.test(finalDesc), 'no model-load chatter on final reply')
t.ok(
views.some((v) => {
const d = v && v.embeds && v.embeds[0] && v.embeds[0].description
return d && /\*\*hello\*\*/.test(d) && !/```[\s\S]*\*\*hello\*\*/.test(d)
}) ||
views.some((v) => /Discord markdown/.test(JSON.stringify(v || {}))),
'agent reply is Discord markdown, not a code fence'
!/^\*\*[A-Za-z0-9_-]+\*\* · `/.test(finalDesc),
'final reply does not start with backend · model · time'
)
t.absent(ctx.env.BARE_OS_AGENT_PLAIN, 'plain env restored')
t.absent(ctx.env.BARE_OS_AGENT_DISCORD, 'discord env restored')
@@ -2024,7 +2031,7 @@ test('Discord /agent is gated on config and runs the guest agent', async (t) =>
t.is(parsedProg.steps[0].tool, 'read_file')
t.is(parsedProg.iteration, 2)
const split = cmds.splitAgentStdout(
'→ read_file\n[process] iteration 1 tools read_file\n**Ready**\n- /bin/ls\n'
'Loading model…\n[qvac] ensuring model QWEN3_1_7B_INST_Q4 (ctx=8192)\n→ read_file\n[process] iteration 1 tools read_file\nDone: listed /bin\n**Ready**\n- /bin/ls\n'
)
t.is(split.answer, '**Ready**\n- /bin/ls')
t.ok(cmds.formatAgentProcess(parsedProg).indexOf('`read_file`') >= 0)
@@ -2908,6 +2915,20 @@ test('Discord /settings browses groups, toggles live flags, and never writes sec
await cmds.settingsApply(ctx, userInstall, '1')
t.is(ctx.vfs.env.DISCORD_USER_INSTALL, '1')
t.ok(/DISCORD_USER_INSTALL=1/.test(tree['~/.discord/.env']))
const presType = cmds.settingsSpecs.find((s) => s.id === 'pres_type')
t.ok(presType && presType.env === 'DISCORD_ACTIVITY_TYPE')
const seenPresence = []
ctx.bareOsDiscordClient = {
user: {
setPresence: (p) => {
seenPresence.push(p)
}
}
}
await cmds.settingsApply(ctx, presType, 'watching')
t.is(ctx.vfs.env.DISCORD_ACTIVITY_TYPE, 'watching')
t.ok(seenPresence.length, 'settings apply presence live')
t.ok(seenPresence[0].activities && seenPresence[0].activities[0].type === 3)
let denied = null
try {
@@ -3039,3 +3060,336 @@ test('process.emitWarning polyfill and reply payload avoid Bare throw', (t) => {
const ws = req('./vendor/bare-discord-js/src/adapters/whatwg-ws.cjs')
t.is(typeof ws.installBareOsProcessEmitWarning, 'function')
})
test('Discord DMs are whitelist-only agent chat; /status updates presence', async (t) => {
const req = createRequire(fileURLToPath(import.meta.url))
const cmds = req('./lib/services/bare-os-discord-commands-guest.cjs')
t.ok(typeof cmds.dispatchMessage === 'function')
t.ok(cmds.isDirectMessage({ channel: { type: 1 }, channelId: 'c' }))
t.absent(cmds.isDirectMessage({ guildId: 'g', channel: { type: 0 } }))
const def = cmds.presenceFromEnv({ env: {} })
t.is(def.status, 'online')
t.is(def.typeName, 'playing')
t.is(def.name, 'Bare OS')
const watch = cmds.presenceFromEnv({
env: {
DISCORD_STATUS: 'idle',
DISCORD_ACTIVITY_TYPE: 'watching',
DISCORD_ACTIVITY_NAME: 'the swarm'
}
})
t.is(watch.status, 'idle')
t.is(watch.type, 3)
t.is(watch.name, 'the swarm')
const off = cmds.presenceFromEnv({ env: { DISCORD_ACTIVITY_NAME: 'off' } })
t.is(off.name, '')
const seen = []
const client = {
user: {
setPresence: (p) => {
seen.push(p)
}
}
}
t.ok(
cmds.applyPresence(
{
env: {
DISCORD_ACTIVITY_TYPE: 'listening',
DISCORD_ACTIVITY_NAME: 'kernel logs',
DISCORD_STATUS: 'dnd'
}
},
client
)
)
t.is(seen[0].status, 'dnd')
t.is(seen[0].activities[0].type, 2)
t.is(seen[0].activities[0].name, 'kernel logs')
const body = cmds.buildSlashCommands({ SlashCommandBuilder: mockSlash() })
const statusCmd = body.find((c) => c.name === 'status')
t.ok(statusCmd, 'slash /status registered')
function makeDm(opts) {
const posted = []
const msg = {
author: { id: opts.uid, bot: !!opts.bot },
content: opts.content || '',
guildId: opts.guildId || null,
guild: opts.guild || null,
channelId: 'dm1',
channel: {
type: opts.guildId ? 0 : 1,
isDMBased: () => !opts.guildId,
sendTyping: async () => {
posted.push({ typing: true })
},
send: async (p) => {
posted.push(p)
return {
id: 'm2',
edit: async (q) => {
posted.push(q)
return q
}
}
}
},
reply: async (p) => {
posted.push(p)
return {
id: 'm1',
edit: async (q) => {
posted.push(q)
return q
}
}
}
}
return { msg: msg, posted: posted }
}
const bot = makeDm({ uid: '111', bot: true, content: 'hello' })
t.absent(await cmds.dispatchMessage({ env: { DISCORD_ID_WHITELIST: '111' } }, bot.msg))
const emptyWl = makeDm({ uid: '111', content: 'hello' })
t.ok(await cmds.dispatchMessage({ env: {} }, emptyWl.msg), 'empty whitelist denies DM')
t.ok(
emptyWl.posted.some((p) => /Access denied/.test(typeof p === 'string' ? p : JSON.stringify(p))),
'empty whitelist DM gets deny text'
)
const stranger = makeDm({ uid: '999', content: 'hello' })
t.ok(
await cmds.dispatchMessage({ env: { DISCORD_ID_WHITELIST: '111' } }, stranger.msg)
)
t.ok(
stranger.posted.some((p) => /Access denied/.test(typeof p === 'string' ? p : JSON.stringify(p)))
)
const helpDm = makeDm({ uid: '111', content: 'help' })
t.ok(
await cmds.dispatchMessage({ env: { DISCORD_ID_WHITELIST: '111' }, vfs: {}, console: {} }, helpDm.msg)
)
t.ok(
helpDm.posted.some((p) => /Direct messages/i.test(JSON.stringify(p || {}))),
'whitelisted DM help'
)
const lines = []
const tree = {
'~/.agent/config.json':
'{"backend":"rest","provider":"groq","rest_api_key":"gsk","rest_base_url":"https://api.groq.com/openai/v1","model":"llama"}\n'
}
const agentDm = makeDm({ uid: '111', content: 'list /bin' })
const ctx = {
env: { DISCORD_ID_WHITELIST: '111', USER: 'alice', HOME: '/home/alice' },
vfs: {
env: { DISCORD_ID_WHITELIST: '111', USER: 'alice', HOME: '/home/alice' },
mkdir: async (p) => {
if (!Array.isArray(tree[p])) tree[p] = []
},
readFile: async (p) => {
if (typeof tree[p] !== 'string') {
const e = new Error('ENOENT')
e.code = 'ENOENT'
throw e
}
return Buffer.from(tree[p])
},
writeFile: async (p, buf) => {
tree[p] = Buffer.from(buf).toString('utf8')
}
},
console: {},
execLine: async (line) => {
lines.push(line)
ctx.console.log('**hello** from DM')
ctx.exitCode = 0
},
bareOsQvacAvailable: () => false
}
t.ok(await cmds.dispatchMessage(ctx, agentDm.msg))
t.ok(
lines.some((l) => /agent /.test(String(l)) && /list \/bin/.test(String(l))),
'whitelisted DM runs guest agent'
)
t.ok(
agentDm.posted.some((p) => /\*\*hello\*\*/.test(JSON.stringify(p || {}))),
'DM reply is the agent answer'
)
const guildPing = makeDm({ uid: '111', content: 'ping', guildId: 'g1', guild: { id: 'g1' } })
t.ok(await cmds.dispatchMessage({ env: { DISCORD_ID_WHITELIST: '111' } }, guildPing.msg))
t.ok(guildPing.posted.some((p) => p === 'pong'), 'guild ping still pongs')
const guildChat = makeDm({
uid: '111',
content: 'please hack the gibson',
guildId: 'g1',
guild: { id: 'g1' }
})
t.absent(
await cmds.dispatchMessage({ env: { DISCORD_ID_WHITELIST: '111' } }, guildChat.msg),
'guild text is not an agent chat'
)
const views = []
await cmds.dispatchInteraction(
{
env: {
DISCORD_ID_WHITELIST: '111',
DISCORD_ACTIVITY_TYPE: 'playing',
DISCORD_ACTIVITY_NAME: 'Bare OS'
},
vfs: {
env: {},
mkdir: async () => {},
writeFile: async () => {},
readFile: async () => {
const e = new Error('ENOENT')
e.code = 'ENOENT'
throw e
}
},
console: {},
bareOsDiscordClient: {
user: {
setPresence: (p) => {
views.push(p)
}
}
}
},
{
isChatInputCommand: () => true,
isAutocomplete: () => false,
isButton: () => false,
isStringSelectMenu: () => false,
commandName: 'status',
user: { id: '111' },
options: {
getSubcommand: () => '',
getString: (k) =>
k === 'activity' ? 'watching' : k === 'name' ? 'the swarm' : k === 'state' ? 'idle' : ''
},
reply: async (p) => {
views.push(p)
}
}
)
t.ok(
views.some((v) => v && v.activities && v.activities[0] && v.activities[0].type === 3),
'/status applies watching presence'
)
t.ok(
views.some((v) => v && v.embeds && /watching/i.test(JSON.stringify(v))),
'/status embed confirms activity'
)
})
test('Discord DM channel lets the agent reach out (whitelist only)', async (t) => {
const req = createRequire(fileURLToPath(import.meta.url))
const cmds = req('./lib/services/bare-os-discord-commands-guest.cjs')
t.ok(typeof cmds.sendChannelMessage === 'function')
t.ok(typeof cmds.bindChannelHook === 'function')
const tree = {}
const sent = []
const ctx = {
env: { DISCORD_ID_WHITELIST: '111' },
vfs: {
env: { DISCORD_ID_WHITELIST: '111' },
mkdir: async () => {},
readFile: async (p) => {
if (typeof tree[p] !== 'string') {
const e = new Error('ENOENT')
e.code = 'ENOENT'
throw e
}
return Buffer.from(tree[p])
},
writeFile: async (p, buf) => {
tree[p] = Buffer.from(buf).toString('utf8')
}
},
console: {},
bareOsDiscordClient: {
users: {
fetch: async (id) => ({
send: async (payload) => {
sent.push({ id: id, payload: payload })
return { id: 'm' }
}
})
}
}
}
const denied = await cmds.sendChannelMessage(ctx, { text: 'hi', userId: '999' })
t.absent(denied.ok, 'cannot DM off-whitelist')
t.is(denied.error, 'whitelist_denied')
t.is(sent.length, 0)
const noPartner = await cmds.sendChannelMessage(
{
env: { DISCORD_ID_WHITELIST: '111,222' },
vfs: {
env: { DISCORD_ID_WHITELIST: '111,222' },
mkdir: ctx.vfs.mkdir,
readFile: ctx.vfs.readFile,
writeFile: ctx.vfs.writeFile
},
console: {}
},
{ text: 'hello' }
)
t.absent(noPartner.ok, 'no partner until someone DMs')
t.is(noPartner.error, 'no_channel_partner')
await cmds.channelRemember(ctx, '111', 'hey bot')
const rec = JSON.parse(tree['~/.discord/channel.json'])
t.is(rec.userId, '111')
t.ok(rec.open)
const inbox = JSON.parse(tree['~/.discord/inbox.json'])
t.ok(inbox.some((m) => m.text === 'hey bot'))
const ok = await cmds.sendChannelMessage(ctx, { text: 'I can reach you' })
t.ok(ok.ok)
t.absent(ok.queued)
t.is(sent.length, 1)
t.is(sent[0].id, '111')
t.is(sent[0].payload.content, 'I can reach you')
const queuedCtx = {
env: { DISCORD_ID_WHITELIST: '111' },
vfs: ctx.vfs,
console: {}
}
const queued = await cmds.sendChannelMessage(queuedCtx, {
text: 'queued while offline',
userId: '111'
})
t.ok(queued.ok && queued.queued)
const outbox = JSON.parse(tree['~/.discord/outbox.json'])
t.ok(outbox.some((m) => m.text === 'queued while offline'))
const drain = await cmds.drainChannelOutbox(ctx)
t.ok(drain.ok)
t.ok(drain.drained >= 1)
t.ok(sent.some((s) => s.payload && s.payload.content === 'queued while offline'))
cmds.bindChannelHook(ctx)
t.ok(typeof ctx.bareOsDiscordSendDm === 'function')
const viaHook = await ctx.bareOsDiscordSendDm({ text: 'via hook' })
t.ok(viaHook.ok)
t.ok(sent.some((s) => s.payload && s.payload.content === 'via hook'))
const st = await cmds.channelStatus(ctx)
t.ok(st.open)
t.is(st.userId, '111')
t.ok(st.liveClient)
})