71 lines
2.5 KiB
TypeScript
71 lines
2.5 KiB
TypeScript
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import os from 'node:os';
|
|
import type { FastifyInstance } from 'fastify';
|
|
import { buildLocalServer } from '../../src/local/index.js';
|
|
|
|
/**
|
|
* Integration test for the pre:memory-write lint handler registered in chat.ts.
|
|
* Fires the real hook through the server's shared HookRegistry and asserts that
|
|
* capability-failure symptoms are cancelled (and routed to the improvement-signal
|
|
* path) while normal memories and dramatic-but-legitimate claims pass through.
|
|
*/
|
|
describe('pre:memory-write capability-symptom lint (handler integration)', () => {
|
|
let server: FastifyInstance;
|
|
let tmpDir: string;
|
|
|
|
beforeAll(async () => {
|
|
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'waggle-memlint-test-'));
|
|
server = await buildLocalServer({ dataDir: tmpDir });
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await server.close();
|
|
await new Promise((r) => setTimeout(r, 100));
|
|
try {
|
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
} catch {
|
|
// Ignore cleanup errors on Windows (EBUSY)
|
|
}
|
|
});
|
|
|
|
it('cancels a capability-failure symptom write and records an improvement signal', async () => {
|
|
const { hookRegistry, orchestrator } = server.agentState;
|
|
const store = orchestrator.getImprovementSignals();
|
|
const before = store.getByCategory('capability_gap').length;
|
|
|
|
const result = await hookRegistry.fire('pre:memory-write', {
|
|
toolName: 'save_memory',
|
|
memoryContent: 'The Slack connector failed to authenticate.',
|
|
});
|
|
|
|
expect(result.cancelled).toBe(true);
|
|
expect(result.reason).toMatch(/capability/i);
|
|
expect(result.reason).toMatch(/acquire_capability/);
|
|
|
|
const after = store.getByCategory('capability_gap');
|
|
expect(after.length).toBe(before + 1);
|
|
});
|
|
|
|
it('allows a normal memory (tool preference) to pass', async () => {
|
|
const { hookRegistry } = server.agentState;
|
|
const result = await hookRegistry.fire('pre:memory-write', {
|
|
toolName: 'save_memory',
|
|
memoryContent: 'User prefers Slack over email for notifications.',
|
|
});
|
|
|
|
expect(result.cancelled).toBe(false);
|
|
});
|
|
|
|
it('does not block a dramatic-but-legitimate claim (warn-only behavior preserved)', async () => {
|
|
const { hookRegistry } = server.agentState;
|
|
const result = await hookRegistry.fire('pre:memory-write', {
|
|
toolName: 'save_memory',
|
|
memoryContent: 'The client wants to cancel the contract immediately, right now.',
|
|
});
|
|
|
|
expect(result.cancelled).toBe(false);
|
|
});
|
|
});
|