import { mkdtemp, rm } from 'fs/promises'; import { tmpdir } from 'os'; import { join } from 'path'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { buildNativeAppManagedBootstrapSpecs, buildNativeAppManagedBootstrapSpecsWithDiagnostics, hashNativeBootstrapText, MAX_NATIVE_BOOTSTRAP_TOTAL_CONTEXT_CHARS, } from '../../../../src/main/services/team/bootstrap/NativeAppManagedBootstrapContextBuilder'; import { TeamMembersMetaStore } from '../../../../src/main/services/team/TeamMembersMetaStore'; import { TeamMetaStore } from '../../../../src/main/services/team/TeamMetaStore'; import { setClaudeBasePathOverride } from '../../../../src/main/utils/pathDecoder'; describe('NativeAppManagedBootstrapContextBuilder', () => { let tempClaudeRoot = ''; beforeEach(async () => { tempClaudeRoot = await mkdtemp(join(tmpdir(), 'native-bootstrap-builder-')); setClaudeBasePathOverride(tempClaudeRoot); }); afterEach(async () => { setClaudeBasePathOverride(null); await rm(tempClaudeRoot, { recursive: true, force: true }); }); it('canonical hash normalizes line endings and trailing whitespace', () => { expect(hashNativeBootstrapText('line 1\r\nline 2 \n')).toBe( hashNativeBootstrapText('line 1\nline 2') ); }); it('builds bounded redacted context for native providers and skips non-native providers', async () => { await new TeamMetaStore().writeMeta('native-ready-team', { cwd: '/tmp/workspace', providerId: 'anthropic', model: 'claude-opus-4-6', createdAt: Date.now(), }); await new TeamMembersMetaStore().writeMembers('native-ready-team', [ { name: 'alice', providerId: 'anthropic', role: 'Reviewer ANTHROPIC_API_KEY=sk-ant-secret ANTHROPIC_AUTH_TOKEN="lmstudio local token"', }, { name: 'bob', providerId: 'codex', role: 'Developer Bearer secret-token', }, { name: 'zoe', providerId: 'gemini', role: 'Gemini member', }, { name: 'tom', providerId: 'opencode', role: 'OpenCode member', }, ]); const specs = await buildNativeAppManagedBootstrapSpecs({ teamName: 'native-ready-team', cwd: '/tmp/workspace', members: [ { name: 'alice', providerId: 'anthropic', role: 'Reviewer ANTHROPIC_API_KEY=sk-ant-secret ANTHROPIC_AUTH_TOKEN="lmstudio local token"', }, { name: 'bob', providerId: 'codex', role: 'Developer Bearer secret-token', }, { name: 'zoe', providerId: 'gemini', role: 'Gemini member', }, { name: 'tom', providerId: 'opencode', role: 'OpenCode member', }, ], }); expect([...specs.keys()].sort()).toEqual(['alice', 'bob']); const alice = specs.get('alice'); const bob = specs.get('bob'); expect(alice?.contextText).toContain(''); expect(alice?.contextText).not.toContain('sk-ant-secret'); expect(alice?.contextText).toContain('ANTHROPIC_API_KEY=[REDACTED]'); expect(alice?.contextText).toContain('ANTHROPIC_AUTH_TOKEN=[REDACTED]'); expect(alice?.contextText).not.toContain('lmstudio'); expect(alice?.contextText).not.toContain('local token'); expect(bob?.contextText).not.toContain('Bearer secret-token'); expect(bob?.contextText).toContain('Bearer [REDACTED]'); expect(bob?.contextText).toContain('Codex Native visible messaging rule'); expect(bob?.contextText).toContain('mcp__agent-teams__task_get'); expect(bob?.contextText).not.toContain('notify your team lead via SendMessage'); expect(alice?.contextHash).toBe(hashNativeBootstrapText(alice?.contextText ?? '')); }); it('warns but still builds for large native rosters below the aggregate budget', async () => { await new TeamMetaStore().writeMeta('large-warning-native-team', { cwd: '/tmp/workspace', providerId: 'anthropic', model: 'claude-opus-4-6', createdAt: Date.now(), }); await new TeamMembersMetaStore().writeMembers( 'large-warning-native-team', Array.from({ length: 7 }, (_, index) => ({ name: `member-${index}`, providerId: 'anthropic' as const, role: 'Developer', })) ); const result = await buildNativeAppManagedBootstrapSpecsWithDiagnostics({ teamName: 'large-warning-native-team', cwd: '/tmp/workspace', members: Array.from({ length: 7 }, (_, index) => ({ name: `member-${index}`, providerId: 'anthropic' as const, role: 'Developer', })), }); expect(result.specs.size).toBe(7); expect(result.diagnostics.nativeMemberCount).toBe(7); expect(result.diagnostics.totalContextLimitChars).toBe( MAX_NATIVE_BOOTSTRAP_TOTAL_CONTEXT_CHARS ); expect(result.diagnostics.warning).toMatch(/Large native team startup context/); }); it('compacts twenty large native contexts within the aggregate budget', async () => { const hugeRole = 'x'.repeat(40_000); await new TeamMetaStore().writeMeta('large-native-team', { cwd: '/tmp/workspace', providerId: 'anthropic', model: 'claude-opus-4-6', createdAt: Date.now(), }); await new TeamMembersMetaStore().writeMembers( 'large-native-team', Array.from({ length: 20 }, (_, index) => ({ name: `member-${index}`, providerId: 'anthropic' as const, role: hugeRole, })) ); const result = await buildNativeAppManagedBootstrapSpecsWithDiagnostics({ teamName: 'large-native-team', cwd: '/tmp/workspace', members: Array.from({ length: 20 }, (_, index) => ({ name: `member-${index}`, providerId: 'anthropic' as const, role: hugeRole, })), }); const totalContextChars = [...result.specs.values()].reduce( (sum, spec) => sum + spec.contextText.length, 0 ); const firstContext = result.specs.get('member-0')?.contextText ?? ''; expect(result.specs.size).toBe(20); expect(totalContextChars).toBeLessThanOrEqual(MAX_NATIVE_BOOTSTRAP_TOTAL_CONTEXT_CHARS); expect(firstContext).toContain('The app loaded compact startup context'); expect(firstContext).toContain('Startup rules:'); expect(firstContext).toContain('Current task briefing:'); expect(firstContext).toContain('[truncated native bootstrap context]'); }); it('keeps Codex MCP rules in compact native startup context', async () => { await new TeamMetaStore().writeMeta('large-codex-native-team', { cwd: '/tmp/workspace', providerId: 'codex', model: 'gpt-5.4-mini', createdAt: Date.now(), }); const members = Array.from({ length: 10 }, (_, index) => ({ name: `member-${index}`, providerId: 'codex' as const, role: 'Developer', model: 'gpt-5.4-mini', })); await new TeamMembersMetaStore().writeMembers('large-codex-native-team', members); const result = await buildNativeAppManagedBootstrapSpecsWithDiagnostics({ teamName: 'large-codex-native-team', cwd: '/tmp/workspace', members, }); const firstContext = result.specs.get('member-0')?.contextText ?? ''; expect(result.specs.size).toBe(10); expect(firstContext).toContain('The app loaded compact startup context'); expect(firstContext).toContain('mcp__agent-teams__task_get'); expect(firstContext).toContain('mcp__agent-teams__member_work_sync_report'); expect(firstContext).toContain('mcp__agent-teams__message_send'); expect(firstContext).toContain('Do not use SendMessage'); }); });