moving
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled

This commit is contained in:
Oleg Maslov
2026-09-02 10:10:29 +02:00
commit 0c3e2ead3b
3841 changed files with 970576 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
/**
* Persona-aware connector recommendations.
*
* Two layers of guards:
* 1. SHAPE — primary lengths in the agreed 35 range, no duplicates,
* fallback for unknown personas, every onboarding persona has a
* matching map entry.
* 2. CATALOG MEMBERSHIP — every connector ID referenced by the
* recommendations actually exists in mcp-catalog.ts. This is the
* bug class we fix here: typos / stale IDs / forward-references
* that ship a recommendation pointing nowhere.
*/
import { describe, it, expect } from 'vitest';
import {
recommendConnectors,
flattenRecommendation,
allReferencedConnectorIds,
CONNECTOR_RECOMMENDATIONS,
} from '../src/connector-recommendations.js';
import { MCP_CATALOG } from '../src/mcp-catalog.js';
const CATALOG_IDS = new Set(MCP_CATALOG.map(s => s.id));
describe('recommendConnectors', () => {
it('returns universal defaults for an unknown persona id', () => {
const r = recommendConnectors('not-a-real-persona-id');
expect(r.primary).toContain('gdrive-mcp');
expect(r.primary).toContain('gmail-mcp');
expect(r.primary).toContain('notion-mcp');
});
it('returns the persona-specific recommendation when the id matches', () => {
const sales = recommendConnectors('sales-rep');
expect(sales.primary).toContain('hubspot-mcp');
expect(sales.primary).toContain('salesforce-mcp');
const coder = recommendConnectors('coder');
expect(coder.primary).toContain('github-mcp');
expect(coder.primary).toContain('linear-mcp');
const consultant = recommendConnectors('consultant');
expect(consultant.primary).toContain('notion-mcp');
expect(consultant.primary).toContain('gdrive-mcp');
});
it('always returns a non-empty primary list (never strands the UI on empty)', () => {
const personaIds = [...Object.keys(CONNECTOR_RECOMMENDATIONS), 'unknown-persona', ''];
for (const id of personaIds) {
const r = recommendConnectors(id);
expect(r.primary.length).toBeGreaterThan(0);
}
});
});
describe('CONNECTOR_RECOMMENDATIONS shape', () => {
it('every recommendation has 3-6 primary entries (Ljiljana-bar cognitive ceiling)', () => {
for (const [personaId, rec] of Object.entries(CONNECTOR_RECOMMENDATIONS)) {
expect(rec.primary.length, `persona "${personaId}" primary out of range`).toBeGreaterThanOrEqual(3);
expect(rec.primary.length, `persona "${personaId}" primary out of range`).toBeLessThanOrEqual(6);
}
});
it('no recommendation has duplicate ids within primary or secondary', () => {
for (const [personaId, rec] of Object.entries(CONNECTOR_RECOMMENDATIONS)) {
const allIds = [...rec.primary, ...rec.secondary];
const dupes = allIds.filter((id, i) => allIds.indexOf(id) !== i);
expect(dupes, `persona "${personaId}" has duplicate connector ids: ${dupes.join(', ')}`).toEqual([]);
}
});
it('every recommended id resolves to a real entry in mcp-catalog.ts', () => {
const referenced = allReferencedConnectorIds();
const missing = referenced.filter(id => !CATALOG_IDS.has(id));
expect(missing, `connector recommendation references ids not in mcp-catalog.ts: ${missing.join(', ')}`).toEqual([]);
});
it('covers every persona id from persona-data.ts (no recommendation drift after a persona is added)', () => {
// The persona list is duplicated here intentionally — importing from
// packages/agent would couple shared->agent, which we don't want for
// a leaf data module. If a persona is added in persona-data.ts but
// not here, this test fails and the fix is a one-line entry.
const ALL_PERSONA_IDS = [
'researcher', 'writer', 'analyst', 'coder',
'project-manager', 'executive-assistant', 'sales-rep', 'marketer',
'product-manager-senior', 'hr-manager', 'legal-professional',
'finance-owner', 'consultant',
'general-purpose', 'planner', 'verifier', 'coordinator',
'support-agent', 'ops-manager', 'data-engineer', 'recruiter',
'creative-director',
];
const recommendedIds = new Set(Object.keys(CONNECTOR_RECOMMENDATIONS));
const missingFromMap = ALL_PERSONA_IDS.filter(id => !recommendedIds.has(id));
expect(missingFromMap, `personas without a CONNECTOR_RECOMMENDATIONS entry: ${missingFromMap.join(', ')}`).toEqual([]);
});
});
describe('flattenRecommendation', () => {
it('returns primary IDs in order, then secondary', () => {
const flat = flattenRecommendation({
primary: ['a', 'b', 'c'],
secondary: ['d', 'e'],
});
expect(flat).toEqual(['a', 'b', 'c', 'd', 'e']);
});
it('preserves primary-first ordering for a real persona', () => {
const flat = flattenRecommendation(recommendConnectors('coder'));
// First five must be the primary list (anchored to github-mcp on top
// because that's the most-load-bearing connector for the coder persona).
expect(flat[0]).toBe('github-mcp');
});
});

View File

@@ -0,0 +1,41 @@
import { describe, it, expect } from 'vitest';
import { LOOP_TEMPLATES } from '../src/loop-templates.js';
describe('LOOP_TEMPLATES (knowledge-worker Loop catalog)', () => {
it('ships a useful set of templates', () => {
expect(LOOP_TEMPLATES.length).toBeGreaterThanOrEqual(5);
});
it('every template id is unique', () => {
const ids = LOOP_TEMPLATES.map(t => t.id);
expect(new Set(ids).size).toBe(ids.length);
});
it('every template has a non-empty name, description, role and prompt', () => {
for (const t of LOOP_TEMPLATES) {
expect(t.name.trim().length, t.id).toBeGreaterThan(0);
expect(t.description.trim().length, t.id).toBeGreaterThan(0);
expect(t.role.trim().length, t.id).toBeGreaterThan(0);
expect(t.jobConfig.prompt.trim().length, t.id).toBeGreaterThan(0);
}
});
it('every defaultCron is a valid 5-field cron expression', () => {
for (const t of LOOP_TEMPLATES) {
const fields = t.defaultCron.trim().split(/\s+/);
expect(fields.length, `${t.id}: "${t.defaultCron}"`).toBe(5);
for (const f of fields) {
expect(/^[\d*,/-]+$/.test(f), `${t.id} field "${f}"`).toBe(true);
}
}
});
it('cadences are daily-or-slower — never a minute/sub-hourly wildcard', () => {
// A Loop is several LLM round-trips; a '*' or '*/n' minute field would burn
// tokens every minute. Templates must use a concrete minute.
for (const t of LOOP_TEMPLATES) {
const minute = t.defaultCron.trim().split(/\s+/)[0];
expect(minute === '*' || minute.includes('/'), `${t.id} fires too often (minute="${minute}")`).toBe(false);
}
});
});

View File

@@ -0,0 +1,54 @@
import { describe, it, expect } from 'vitest';
import {
RISK_LEVELS, APPROVAL_CLASSES, TRUST_SOURCES, ASSESSMENT_MODES,
AUDIT_ACTIONS, AUDIT_CAPABILITY_TYPES, AUDIT_INITIATORS,
riskRank, riskAtLeast, sqlInList,
} from '../src/risk.js';
describe('canonical risk taxonomy (A1) — widest-set parity', () => {
it('RiskLevel adopts the audit set (adds critical)', () => {
expect([...RISK_LEVELS]).toEqual(['low', 'medium', 'high', 'critical']);
});
it('ApprovalClass adopts the audit set (adds blocked)', () => {
expect([...APPROVAL_CLASSES]).toEqual(['standard', 'elevated', 'critical', 'blocked']);
});
it('TrustSource is the 7-value set incl. security-gate', () => {
expect([...TRUST_SOURCES]).toEqual([
'builtin', 'starter_pack', 'local_user', 'third_party_verified',
'third_party_unverified', 'unknown', 'security-gate',
]);
});
it('AssessmentMode is declared/heuristic/mixed', () => {
expect([...ASSESSMENT_MODES]).toEqual(['declared', 'heuristic', 'mixed']);
});
it('AuditAction includes uninstalled (P5/D4)', () => {
expect([...AUDIT_ACTIONS]).toEqual([
'proposed', 'approved', 'installed', 'rejected', 'failed', 'blocked', 'uninstalled',
]);
});
it('AuditCapabilityType + AuditInitiator match the store', () => {
expect([...AUDIT_CAPABILITY_TYPES]).toEqual(['native', 'skill', 'plugin', 'mcp', 'connector', 'marketplace']);
expect([...AUDIT_INITIATORS]).toEqual(['agent', 'user', 'system']);
});
});
describe('risk ordering helpers', () => {
it('riskRank orders ascending, critical highest', () => {
expect(riskRank('low')).toBe(0);
expect(riskRank('critical')).toBe(3);
expect(riskRank('critical')).toBeGreaterThan(riskRank('low'));
});
it('riskAtLeast compares on the canonical scale (critical >= low, not below)', () => {
expect(riskAtLeast('critical', 'low')).toBe(true);
expect(riskAtLeast('low', 'high')).toBe(false);
expect(riskAtLeast('high', 'high')).toBe(true);
});
});
describe('sqlInList — CHECK-constraint single source', () => {
it('quotes and comma-joins for a SQLite IN clause', () => {
expect(sqlInList(AUDIT_ACTIONS)).toBe(
"'proposed', 'approved', 'installed', 'rejected', 'failed', 'blocked', 'uninstalled'",
);
});
});

View File

@@ -0,0 +1,89 @@
import { describe, it, expect } from 'vitest';
import {
createTeamSchema,
createTaskSchema,
sendMessageSchema,
createAgentSchema,
createAgentGroupSchema,
} from '../src/schemas.js';
describe('createTeamSchema', () => {
it('accepts valid team', () => {
const result = createTeamSchema.safeParse({ name: 'Marketing', slug: 'marketing' });
expect(result.success).toBe(true);
});
it('rejects empty name', () => {
const result = createTeamSchema.safeParse({ name: '', slug: 'ok' });
expect(result.success).toBe(false);
});
it('rejects invalid slug characters', () => {
const result = createTeamSchema.safeParse({ name: 'Ok', slug: 'Has Spaces' });
expect(result.success).toBe(false);
});
});
describe('createTaskSchema', () => {
it('accepts valid task with defaults', () => {
const result = createTaskSchema.safeParse({ title: 'Research competitors' });
expect(result.success).toBe(true);
if (result.success) {
expect(result.data.priority).toBe('normal');
}
});
});
describe('sendMessageSchema', () => {
it('accepts valid waggle dance message', () => {
const result = sendMessageSchema.safeParse({
type: 'request',
subtype: 'knowledge_check',
content: { topic: 'competitor pricing', scope: 'Product Line X' },
});
expect(result.success).toBe(true);
});
it('rejects invalid subtype', () => {
const result = sendMessageSchema.safeParse({
type: 'broadcast',
subtype: 'invalid_type',
content: {},
});
expect(result.success).toBe(false);
});
});
describe('createAgentSchema', () => {
it('accepts agent with defaults', () => {
const result = createAgentSchema.safeParse({ name: 'web-searcher' });
expect(result.success).toBe(true);
if (result.success) {
expect(result.data.model).toBe('claude-haiku-4-5');
expect(result.data.tools).toEqual([]);
}
});
});
describe('createAgentGroupSchema', () => {
it('accepts valid agent group', () => {
const result = createAgentGroupSchema.safeParse({
name: 'Research Team',
strategy: 'parallel',
members: [
{ agentId: '00000000-0000-0000-0000-000000000001', roleInGroup: 'lead' },
{ agentId: '00000000-0000-0000-0000-000000000002' },
],
});
expect(result.success).toBe(true);
});
it('rejects invalid strategy', () => {
const result = createAgentGroupSchema.safeParse({
name: 'Bad',
strategy: 'random',
members: [],
});
expect(result.success).toBe(false);
});
});

View File

@@ -0,0 +1,41 @@
import { describe, it, expect } from 'vitest';
import {
BUILTIN_TOOL_MANIFESTS, SUPPORTED_TOOLS, LAUNCH_COHORT, TOOL_DISPLAY_NAMES,
applyPromptArgTemplate,
} from '../src/tool-detection.js';
describe('BUILTIN_TOOL_MANIFESTS', () => {
it('has one manifest per supported tool, ids matching SUPPORTED_TOOLS', () => {
expect(BUILTIN_TOOL_MANIFESTS.map((m) => m.id).sort()).toEqual([...SUPPORTED_TOOLS].sort());
});
it('marks every built-in as builtin:true and launchable', () => {
for (const m of BUILTIN_TOOL_MANIFESTS) {
expect(m.builtin).toBe(true);
expect(m.launchable).toBe(true);
}
});
it('every built-in is hook-capable', () => {
expect(BUILTIN_TOOL_MANIFESTS.filter((m) => !m.hookCapable)).toEqual([]);
});
it('derives TOOL_DISPLAY_NAMES + LAUNCH_COHORT from the manifests (unchanged values)', () => {
expect(TOOL_DISPLAY_NAMES['claude-code']).toBe('Claude Code');
expect(TOOL_DISPLAY_NAMES['codex']).toBe('Codex CLI');
expect([...LAUNCH_COHORT].sort()).toEqual([...SUPPORTED_TOOLS].sort());
});
it('claude-code detects by PATH binary "claude" (not its id)', () => {
const cc = BUILTIN_TOOL_MANIFESTS.find((m) => m.id === 'claude-code')!;
expect(cc.detect).toEqual({ kind: 'path', binaryName: 'claude' });
});
});
describe('applyPromptArgTemplate (#5 fast-follow)', () => {
it('substitutes {prompt} in each template entry', () => {
expect(applyPromptArgTemplate(['--print', '{prompt}'], 'hello')).toEqual(['--print', 'hello']);
});
it('substitutes within an entry and across multiple entries', () => {
expect(applyPromptArgTemplate(['-m', 'msg={prompt}', '{prompt}'], 'hi')).toEqual(['-m', 'msg=hi', 'hi']);
});
it('leaves entries without the placeholder untouched', () => {
expect(applyPromptArgTemplate(['--yes', '--fast'], 'hi')).toEqual(['--yes', '--fast']);
});
});