diff --git a/.agents/skills/beadboard-driver/scripts/bb-mail-shim.mjs b/.agents/skills/beadboard-driver/scripts/bb-mail-shim.mjs new file mode 100644 index 0000000..ae405b1 --- /dev/null +++ b/.agents/skills/beadboard-driver/scripts/bb-mail-shim.mjs @@ -0,0 +1,135 @@ +#!/usr/bin/env node +/** + * bb-mail-shim.mjs + * Translates bd mail delegate calls into bb agent coordination commands. + * + * bd mail delegates by prepending the configured delegate string to all args: + * `bd mail inbox` → `node bb-mail-shim.mjs inbox` + * `bd mail send --to foo ...` → `node bb-mail-shim.mjs send --to foo ...` + * + * Agent identity is read from (in order): + * 1. BB_AGENT env var (e.g., export BB_AGENT=silver-scribe) + * 2. BD_ACTOR env var (git actor name used by bd commands) + * + * Command mappings: + * bd mail inbox [--state s] [--bead b] [--limit n] + * → bb agent inbox --agent [...] + * + * bd mail send --to --bead --category --subject --body + * → bb agent send --from --to --bead --category --subject --body + * (--from injected automatically; omitted if caller already supplies it) + * + * bd mail read + * → bb agent read --agent --message + * + * bd mail ack + * → bb agent ack --agent --message + * + * bd mail [...] (passthrough) + * → bb agent [...] + * + * To configure (one-time, or via session-preflight.mjs): + * bd config set mail.delegate "node /abs/path/to/bb-mail-shim.mjs" + * + * Note: bb agent commands must be available globally (installed via izs.2). + * Until then, call tools/bb.ts from the BeadBoard repo directly. + */ +import { spawnSync } from 'node:child_process'; + +function getAgentName() { + const agent = (process.env.BB_AGENT || process.env.BD_ACTOR || '').trim(); + if (!agent) { + console.error( + 'bb-mail-shim: agent identity required.\n' + + 'Set BB_AGENT to your agent name before using bd mail:\n' + + ' export BB_AGENT=silver-scribe\n' + + 'Or ensure BD_ACTOR is set by your bd environment.', + ); + process.exit(1); + } + return agent; +} + +function runBbAgent(args) { + const result = spawnSync('bb', ['agent', ...args], { stdio: 'inherit', shell: false }); + if (result.error) { + if (result.error.code === 'ENOENT') { + console.error( + 'bb-mail-shim: bb command not found in PATH.\n' + + 'Install the BeadBoard global CLI so bb agent commands are available.\n' + + 'Interim: call tools/bb.ts directly from the BeadBoard repo:\n' + + ' node --import tsx /path/to/beadboard/tools/bb.ts agent inbox --agent $BB_AGENT', + ); + } else { + console.error(`bb-mail-shim: failed to spawn bb: ${result.error.message}`); + } + process.exit(1); + } + process.exit(result.status ?? 0); +} + +const args = process.argv.slice(2); +const subcommand = args[0]; + +if (!subcommand || subcommand === '--help' || subcommand === '-h') { + console.log(`bb-mail-shim: bd mail → bb agent translation shim + +Usage (via bd mail after delegate is configured): + bd mail inbox [--state unread|read|acked] [--bead ] [--limit ] + bd mail send --to --bead --category HANDOFF|BLOCKED|DECISION|INFO --subject --body + bd mail read + bd mail ack + +Requires: BB_AGENT or BD_ACTOR env var set to your agent name. + +Configure once per project: + bd config set mail.delegate "node /abs/path/to/bb-mail-shim.mjs" + # or run session-preflight.mjs which sets this automatically`); + process.exit(0); +} + +const agent = getAgentName(); + +switch (subcommand) { + case 'inbox': { + // bd mail inbox [...] → bb agent inbox --agent [...] + runBbAgent(['inbox', '--agent', agent, ...args.slice(1)]); + break; + } + + case 'send': { + // bd mail send [...] → bb agent send --from [...] + // Inject --from only if caller hasn't already supplied it + const rest = args.slice(1); + const hasFrom = rest.includes('--from'); + runBbAgent(['send', ...(hasFrom ? [] : ['--from', agent]), ...rest]); + break; + } + + case 'read': { + // bd mail read [...] → bb agent read --agent --message [...] + const msgId = args[1]; + if (!msgId) { + console.error('bb-mail-shim: "read" requires a argument'); + process.exit(1); + } + runBbAgent(['read', '--agent', agent, '--message', msgId, ...args.slice(2)]); + break; + } + + case 'ack': { + // bd mail ack [...] → bb agent ack --agent --message [...] + const msgId = args[1]; + if (!msgId) { + console.error('bb-mail-shim: "ack" requires a argument'); + process.exit(1); + } + runBbAgent(['ack', '--agent', agent, '--message', msgId, ...args.slice(2)]); + break; + } + + default: { + // Passthrough for any other subcommand + runBbAgent([subcommand, ...args.slice(1)]); + } +} diff --git a/.agents/skills/beadboard-driver/scripts/session-preflight.mjs b/.agents/skills/beadboard-driver/scripts/session-preflight.mjs index 2bb3e54..93945bc 100644 --- a/.agents/skills/beadboard-driver/scripts/session-preflight.mjs +++ b/.agents/skills/beadboard-driver/scripts/session-preflight.mjs @@ -1,8 +1,56 @@ #!/usr/bin/env node +import { spawnSync } from 'node:child_process'; +import { existsSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; + import { findCommandInPath, resolveBbPath } from './lib/driver-lib.mjs'; +const __dirname = dirname(fileURLToPath(import.meta.url)); + +/** + * Configures bd mail delegate to use bb-mail-shim.mjs. + * Runs `bd config set mail.delegate "node "` in the current directory. + * + * @param {string} bdPath - Resolved path to the bd binary. + * @param {string} shimPath - Absolute path to bb-mail-shim.mjs. + * @returns {object} Mail delegate config result. + */ +function configureMailDelegate(bdPath, shimPath) { + if (!existsSync(shimPath)) { + return { + configured: false, + reason: `shim not found at ${shimPath} — skill installation may be incomplete`, + }; + } + + const delegateCmd = `node ${shimPath}`; + const result = spawnSync(bdPath, ['config', 'set', 'mail.delegate', delegateCmd], { + stdio: 'pipe', + shell: false, + }); + + if (result.status !== 0) { + const stderr = result.stderr?.toString().trim() || ''; + return { + configured: false, + reason: `bd config set failed: ${stderr || 'non-zero exit'}`, + delegate: delegateCmd, + }; + } + + return { + configured: true, + delegate: delegateCmd, + shim_path: shimPath, + note: 'Set BB_AGENT env var to your agent name before calling bd mail (e.g., export BB_AGENT=silver-scribe)', + }; +} + async function main() { + const shimPath = join(__dirname, 'bb-mail-shim.mjs'); + try { const bdPath = await findCommandInPath('bd'); if (!bdPath) { @@ -17,6 +65,7 @@ async function main() { bd: { available: false, path: null }, }, bb: null, + mail: null, }, null, 2, @@ -38,6 +87,10 @@ async function main() { bd: { available: true, path: bdPath }, }, bb, + mail: { + configured: false, + reason: 'bb not available — mail delegate requires bb agent commands (see izs.2)', + }, }, null, 2, @@ -46,6 +99,8 @@ async function main() { return; } + const mail = configureMailDelegate(bdPath, shimPath); + process.stdout.write( `${JSON.stringify( { @@ -55,6 +110,7 @@ async function main() { bd: { available: true, path: bdPath }, }, bb, + mail, }, null, 2, @@ -67,11 +123,12 @@ async function main() { ok: false, error_code: 'PREFLIGHT_INTERNAL_ERROR', reason: error instanceof Error ? error.message : String(error), - remediation: 'Inspect session-preflight.js and retry.', + remediation: 'Inspect session-preflight.mjs and retry.', tools: { bd: { available: false, path: null }, }, bb: null, + mail: null, }, null, 2,