Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
188 lines
6.7 KiB
TypeScript
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('');
|
|
});
|
|
});
|