import { describe, expect, test } from 'bun:test'; import { serveConfigContent, affordancesPath } from './serve-env'; // The config shape is a contract with the OpenCode binary, and the cost of a wrong key name is SILENCE: // no error, no warning, just an agent that never sees a skill. So the keys are asserted literally. describe('serveConfigContent', () => { test('names skills.paths and instructions exactly', () => { const parsed = JSON.parse(serveConfigContent(['/a/skills', '/b/skills'], ['/tmp/aff.md'], 'PROMPT')); expect(parsed.skills).toEqual({ paths: ['/a/skills', '/b/skills'] }); expect(parsed.instructions).toEqual(['/tmp/aff.md']); // The agent is what a session is created with; a config without it silently falls back to // OpenCode's coding-agent framing, which is the bug this whole file exists to stop. expect(parsed.default_agent).toBe('officer'); expect(parsed.agent.officer.prompt).toBe('PROMPT'); expect(parsed.agent.officer.mode).toBe('primary'); }); // An empty array is not the same as an absent key: `skills: {paths: []}` is a claim that there are none, // and merged over a config that sets some it would erase them. test('omits a key rather than sending it empty', () => { expect(JSON.parse(serveConfigContent([], [], 'P')).skills).toBeUndefined(); expect(JSON.parse(serveConfigContent(['/a'], [], 'P')).skills).toEqual({ paths: ['/a'] }); }); test('is valid JSON for an env var — no newlines to be mangled by a shell', () => { expect(serveConfigContent(['/a/skills'], ['/tmp/aff.md'], 'P')).not.toContain('\n'); }); test('the affordances file sits beside the serve state, not in a home', () => { expect(affordancesPath('/data/opencode_server')).toBe('/data/opencode_server/officer-affordances.md'); }); });