Files
stack/packages/mosaic/src/fleet/comms-onboarding.spec.ts
Jason Woltje 095e19443b
All checks were successful
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
feat(fleet): onboarding-injection — comms cheat-sheet + peer roster per agent (#621)
Co-authored-by: Jason Woltje <jason@diversecanvas.com>
Co-committed-by: Jason Woltje <jason@diversecanvas.com>
2026-06-22 17:54:54 +00:00

188 lines
6.7 KiB
TypeScript

import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import {
parseRosterAgents,
buildFleetCommsBlock,
renderPeerReach,
readFleetCommsBlock,
type CommsPeer,
} from './comms-onboarding.js';
const ROSTER = [
'version: 1',
'transport: tmux',
'agents:',
' - name: orchestrator',
' runtime: claude',
' class: orchestrator',
' - name: enhancer',
' runtime: claude',
' class: enhancer',
' - name: coder0',
' runtime: pi',
' class: implementer',
' # a manually-listed cross-host peer (pre-federation stopgap)',
' - name: coder0-0',
' runtime: claude',
' class: implementer',
' host: 10.1.10.37',
' ssh: jwoltje@10.1.10.37',
'',
].join('\n');
describe('parseRosterAgents', () => {
it('parses name + class + optional host/ssh', () => {
const peers = parseRosterAgents(ROSTER);
expect(peers.map((p) => p.name)).toEqual(['orchestrator', 'enhancer', 'coder0', 'coder0-0']);
expect(peers.find((p) => p.name === 'coder0')).toMatchObject({ className: 'implementer' });
expect(peers.find((p) => p.name === 'coder0-0')).toMatchObject({
className: 'implementer',
host: '10.1.10.37',
ssh: 'jwoltje@10.1.10.37',
});
// local agents have no host/ssh
expect(peers.find((p) => p.name === 'orchestrator')!.host).toBeUndefined();
});
it('parses an optional per-agent socket', () => {
const peers = parseRosterAgents(
['agents:', ' - name: a', ' class: worker', ' socket: mosaic-factory'].join('\n'),
);
expect(peers[0]).toMatchObject({ name: 'a', socket: 'mosaic-factory' });
});
it('stops at the next top-level key', () => {
const peers = parseRosterAgents(
['agents:', ' - name: a', ' class: worker', 'defaults:', ' working_directory: ~'].join(
'\n',
),
);
expect(peers.map((p) => p.name)).toEqual(['a']);
});
});
describe('renderPeerReach — same-host vs cross-host', () => {
const send = '/home/u/.config/mosaic/tools/tmux/agent-send.sh';
it('renders the short form for a same-host peer', () => {
const peer: CommsPeer = { name: 'enhancer', className: 'enhancer' };
expect(renderPeerReach(peer, 'w-jarvis', send)).toBe(`${send} -s enhancer -m "…"`);
});
it('renders the -H form for a cross-host peer using ssh', () => {
const peer: CommsPeer = {
name: 'coder0-0',
className: 'implementer',
host: '10.1.10.37',
ssh: 'jwoltje@10.1.10.37',
};
expect(renderPeerReach(peer, 'w-jarvis', send)).toBe(
`${send} -H jwoltje@10.1.10.37 -s coder0-0 -m "…"`,
);
});
it('falls back to host when a cross-host peer has no ssh', () => {
const peer: CommsPeer = { name: 'x', className: 'worker', host: '10.0.0.9' };
expect(renderPeerReach(peer, 'w-jarvis', send)).toBe(`${send} -H 10.0.0.9 -s x -m "…"`);
});
it('treats a peer whose host equals the fleet host as same-host', () => {
const peer: CommsPeer = { name: 'y', className: 'worker', host: 'w-jarvis' };
expect(renderPeerReach(peer, 'w-jarvis', send)).toBe(`${send} -s y -m "…"`);
});
it('emits NO -L for an unset/default socket', () => {
const peer: CommsPeer = { name: 'lead', className: 'orchestrator' };
expect(renderPeerReach(peer, 'w-jarvis', send)).toBe(`${send} -s lead -m "…"`);
});
it('emits -L <socket> for a named socket', () => {
const peer: CommsPeer = { name: 'coder0', className: 'implementer', socket: 'mosaic-factory' };
expect(renderPeerReach(peer, 'w-jarvis', send)).toBe(
`${send} -L mosaic-factory -s coder0 -m "…"`,
);
});
it('combines -L (named socket) and -H (cross-host) in order', () => {
const peer: CommsPeer = {
name: 'coder0-0',
className: 'implementer',
host: '10.1.10.37',
ssh: 'jwoltje@10.1.10.37',
socket: 'mosaic-factory',
};
expect(renderPeerReach(peer, 'w-jarvis', send)).toBe(
`${send} -L mosaic-factory -H jwoltje@10.1.10.37 -s coder0-0 -m "…"`,
);
});
});
describe('buildFleetCommsBlock', () => {
const send = '/h/.config/mosaic/tools/tmux/agent-send.sh';
const agents = parseRosterAgents(ROSTER);
it('excludes self, lists peers, flags the orchestrator, and emits both address forms', () => {
const block = buildFleetCommsBlock({
selfName: 'enhancer',
agents,
fleetHost: 'w-jarvis',
agentSendPath: send,
});
expect(block).toContain('# Fleet Comms');
expect(block).toContain('You are **enhancer**');
// criterion 1: agent's own [host:session] identity
expect(block).toContain('`[w-jarvis:enhancer]`');
// self excluded
expect(block).not.toMatch(/\|\s*enhancer\s*\|/);
// peers present
expect(block).toContain('| orchestrator |');
expect(block).toContain('point of contact');
// same-host peer short form
expect(block).toContain(`${send} -s coder0 -m "…"`);
// cross-host peer -H form + host annotation
expect(block).toContain(`${send} -H jwoltje@10.1.10.37 -s coder0-0 -m "…"`);
expect(block).toContain('host `10.1.10.37`');
// conventions
expect(block).toContain('FLIP the preamble');
expect(block).toContain('ACCEPTED');
});
it('returns empty when the agent has no peers', () => {
expect(
buildFleetCommsBlock({
selfName: 'solo',
agents: [{ name: 'solo', className: 'orchestrator' }],
fleetHost: 'h',
agentSendPath: send,
}),
).toBe('');
});
});
describe('readFleetCommsBlock — situational (the context a spawned agent gets)', () => {
let home: string;
beforeEach(() => {
home = mkdtempSync(join(tmpdir(), 'mosaic-comms-'));
mkdirSync(join(home, 'fleet'), { recursive: true });
writeFileSync(join(home, 'fleet', 'roster.yaml'), ROSTER);
});
afterEach(() => rmSync(home, { recursive: true, force: true }));
it('builds the cheat-sheet with correct peer addresses for a fleet member', () => {
const block = readFleetCommsBlock(home, 'orchestrator', 'w-jarvis');
expect(block).toContain('# Fleet Comms');
expect(block).toContain('| enhancer |');
expect(block).toContain(`${join(home, 'tools', 'tmux', 'agent-send.sh')} -s coder0 -m "…"`);
expect(block).toContain('-H jwoltje@10.1.10.37 -s coder0-0');
expect(block).not.toMatch(/\|\s*orchestrator\s*\|/); // self excluded
});
it('returns empty when MOSAIC_AGENT_NAME is unset, no roster, or agent not a member', () => {
expect(readFleetCommsBlock(home, undefined, 'w-jarvis')).toBe('');
expect(readFleetCommsBlock(home, 'stranger', 'w-jarvis')).toBe('');
expect(readFleetCommsBlock(mkdtempSync(join(tmpdir(), 'noroster-')), 'orchestrator')).toBe('');
});
});