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,112 @@
import { describe, it, expect } from 'vitest';
import {
HookRegistry,
Plan,
PermissionManager,
READONLY_TOOLS,
filterToolsForContext,
needsConfirmation,
ConfirmationGate,
MemoryLinker,
} from '@waggle/agent';
import { Ontology, validateEntity } from '@waggle/core';
describe('M3c Integration', () => {
it('hook registry registers and fires', async () => {
const registry = new HookRegistry();
const calls: string[] = [];
registry.on('pre:tool', async (ctx) => { calls.push(`pre:${ctx.toolName}`); });
registry.on('post:tool', async (ctx) => { calls.push(`post:${ctx.toolName}`); });
await registry.fire('pre:tool', { toolName: 'bash' });
await registry.fire('post:tool', { toolName: 'bash' });
expect(calls).toEqual(['pre:bash', 'post:bash']);
});
it('permission manager blocks blacklisted tools', () => {
const pm = new PermissionManager({ blacklist: ['bash'] });
expect(pm.isAllowed('bash')).toBe(false);
expect(pm.isAllowed('read_file')).toBe(true);
});
it('sandbox mode restricts to readonly tools', () => {
const pm = PermissionManager.sandbox();
expect(pm.isAllowed('read_file')).toBe(true);
expect(pm.isAllowed('bash')).toBe(false);
expect(pm.isAllowed('write_file')).toBe(false);
});
it('plan mode creates, advances, and completes', () => {
const plan = new Plan();
plan.addStep({ title: 'Step 1' });
plan.addStep({ title: 'Step 2' });
expect(plan.getCurrentStep()?.title).toBe('Step 1');
plan.completeCurrentStep('done');
expect(plan.getCurrentStep()?.title).toBe('Step 2');
plan.completeCurrentStep('done');
expect(plan.isComplete()).toBe(true);
});
it('tool filtering narrows by context', () => {
const tools = [
{ name: 'bash', description: '', parameters: {}, execute: async () => '' },
{ name: 'read_file', description: '', parameters: {}, execute: async () => '' },
{ name: 'web_search', description: '', parameters: {}, execute: async () => '' },
];
const research = filterToolsForContext(tools, 'research');
expect(research.map(t => t.name)).toContain('read_file');
expect(research.map(t => t.name)).toContain('web_search');
expect(research.map(t => t.name)).not.toContain('bash');
});
it('confirmation gates identify sensitive ops', () => {
expect(needsConfirmation('bash')).toBe(true);
expect(needsConfirmation('write_file')).toBe(true);
expect(needsConfirmation('read_file')).toBe(false);
expect(needsConfirmation('git_commit')).toBe(true);
});
it('ontology validates entities', () => {
const ontology = new Ontology();
ontology.define('person', { required: ['name'], optional: ['email'] });
const valid = validateEntity(ontology, { type: 'person', properties: { name: 'Alice' } });
expect(valid.valid).toBe(true);
const invalid = validateEntity(ontology, { type: 'person', properties: { email: 'a@b.com' } });
expect(invalid.valid).toBe(false);
expect(invalid.issues).toContain('Missing required property: name');
});
it('all M3c modules integrate without conflicts', async () => {
// Create all components — verify no import/construction errors
const hooks = new HookRegistry();
const plan = new Plan();
const permissions = PermissionManager.sandbox();
const gate = new ConfirmationGate({ interactive: false });
const ontology = new Ontology();
// Wire hooks into permission check
hooks.on('pre:tool', async (ctx) => {
if (!permissions.isAllowed(ctx.toolName!)) {
return { cancel: true, reason: 'Not allowed by permissions' };
}
});
// Fire for allowed tool
const r1 = await hooks.fire('pre:tool', { toolName: 'read_file' });
expect(r1.cancelled).toBe(false);
// Fire for blocked tool
const r2 = await hooks.fire('pre:tool', { toolName: 'bash' });
expect(r2.cancelled).toBe(true);
// Confirmation auto-approves in non-interactive
const approved = await gate.confirm('bash', {});
expect(approved).toBe(true);
// Plan works
plan.addStep({ title: 'Research' });
plan.completeCurrentStep('Found info');
expect(plan.isComplete()).toBe(true);
});
});