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,168 @@
/**
* AwarenessLayer tests — full-file port from
* hive-mind/packages/core/src/mind/awareness.test.ts.
*
* Memory Sync Repair Step 2. Source: hive-mind file at HEAD c363257.
*
* Filename suffix `-hive-mind` keeps this distinct from waggle-os's own
* `awareness.test.ts`. Hive-mind covers metadata round-trip,
* updateMetadata semantics, and getByStatus — surfaces waggle-os's own
* file does not exercise.
*
* Adapted imports: `./db.js`, `./awareness.js` → `../../src/mind/...`.
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { rmSync, existsSync } from 'node:fs';
import { MindDB } from '../../src/mind/db.js';
import { AwarenessLayer } from '../../src/mind/awareness.js';
describe('AwarenessLayer (hive-mind port)', () => {
let dbPath: string;
let db: MindDB;
let awareness: AwarenessLayer;
beforeEach(() => {
dbPath = join(tmpdir(), `waggle-mind-awareness-test-${Date.now()}-${Math.random()}.mind`);
db = new MindDB(dbPath);
awareness = new AwarenessLayer(db);
});
afterEach(() => {
db.close();
if (existsSync(dbPath)) rmSync(dbPath);
for (const suffix of ['-shm', '-wal']) {
if (existsSync(dbPath + suffix)) rmSync(dbPath + suffix);
}
});
it('add() inserts a row with defaults and get() round-trips it', () => {
const item = awareness.add('task', 'review PR #42');
expect(item.category).toBe('task');
expect(item.content).toBe('review PR #42');
expect(item.priority).toBe(0);
expect(item.expires_at).toBeNull();
expect(JSON.parse(item.metadata)).toEqual({});
const loaded = awareness.get(item.id);
expect(loaded?.id).toBe(item.id);
});
it('add() with metadata stores it as JSON and parseMetadata reads it back', () => {
const item = awareness.add('action', 'ran tests', 5, undefined, {
context: 'CI pipeline',
status: 'success',
});
const meta = awareness.parseMetadata(item);
expect(meta.context).toBe('CI pipeline');
expect(meta.status).toBe('success');
});
it('update() rewrites fields and leaves others unchanged', () => {
const item = awareness.add('pending', 'waiting for review', 2);
const updated = awareness.update(item.id, { priority: 9 });
expect(updated.priority).toBe(9);
expect(updated.content).toBe('waiting for review');
const same = awareness.update(item.id, {});
expect(same.priority).toBe(9);
});
it('updateMetadata() merges into existing metadata without replacing untouched keys', () => {
const item = awareness.add('flag', 'context-switch', 0, undefined, {
context: 'onboarding',
});
const merged = awareness.updateMetadata(item.id, { status: 'in_progress' });
const meta = awareness.parseMetadata(merged);
expect(meta.context).toBe('onboarding');
expect(meta.status).toBe('in_progress');
});
it('updateMetadata() throws for unknown ids', () => {
expect(() => awareness.updateMetadata(9999, { status: 'x' })).toThrow(
/Awareness item 9999 not found/,
);
});
it('getAll() orders by priority desc and caps at MAX_ITEMS (10)', () => {
for (let i = 0; i < 15; i++) {
awareness.add('task', `task ${i}`, i);
}
const all = awareness.getAll();
expect(all).toHaveLength(10);
expect(all[0].priority).toBe(14);
expect(all[9].priority).toBe(5);
});
it('getByCategory() filters by category and respects the MAX_ITEMS cap', () => {
for (let i = 0; i < 12; i++) awareness.add('task', `t${i}`, i);
awareness.add('flag', 'f-only', 100);
const tasks = awareness.getByCategory('task');
expect(tasks).toHaveLength(10);
expect(tasks.every((t) => t.category === 'task')).toBe(true);
const flags = awareness.getByCategory('flag');
expect(flags).toHaveLength(1);
expect(flags[0].content).toBe('f-only');
});
it('getByStatus() returns only items whose metadata.status matches', () => {
awareness.add('action', 'a1', 0, undefined, { status: 'done' });
awareness.add('action', 'a2', 0, undefined, { status: 'pending' });
awareness.add('action', 'a3', 0, undefined, { status: 'done' });
const done = awareness.getByStatus('done').map((i) => i.content).sort();
expect(done).toEqual(['a1', 'a3']);
});
it('expired items are excluded from getAll() / getByCategory()', () => {
const pastIso = new Date(Date.now() - 60_000).toISOString();
const futureIso = new Date(Date.now() + 60_000).toISOString();
awareness.add('task', 'expired', 0, pastIso);
const alive = awareness.add('task', 'alive', 0, futureIso);
const visible = awareness.getAll().map((i) => i.id);
expect(visible).toEqual([alive.id]);
const tasks = awareness.getByCategory('task').map((i) => i.id);
expect(tasks).toEqual([alive.id]);
});
it('remove() / clear() / clearCategory() delete rows as expected', () => {
const a = awareness.add('task', 'a');
awareness.add('task', 'b');
awareness.add('flag', 'c');
awareness.remove(a.id);
expect(awareness.get(a.id)).toBeUndefined();
awareness.clearCategory('task');
expect(awareness.getByCategory('task')).toEqual([]);
expect(awareness.getByCategory('flag')).toHaveLength(1);
awareness.clear();
expect(awareness.getAll()).toEqual([]);
});
it('toContext() renders section headers per non-empty category, skipping empty ones', () => {
awareness.add('task', 'T1', 1);
awareness.add('task', 'T2', 0);
awareness.add('flag', 'F1', 0);
const ctx = awareness.toContext();
expect(ctx).toContain('Active Tasks:');
expect(ctx).toContain('- T1');
expect(ctx).toContain('- T2');
expect(ctx).toContain('Context Flags:');
expect(ctx).toContain('- F1');
expect(ctx).not.toContain('Recent Actions:');
expect(ctx).not.toContain('Pending Items:');
});
it('toContext() returns a sentinel message when there is no active content', () => {
expect(awareness.toContext()).toBe('No active awareness items.');
});
});