/** * Smoke test: buildSystemPrompt injects "## Subscribed Notes" when the * job owner has inject-mode subscriptions, and omits it when they don't. */ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import Database from 'better-sqlite3'; import { mkdtempSync, rmSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; import { runMigrations } from '../db/migrate.js'; import { NotesRepository } from '../notes/notes-repository.js'; import { NotesService } from '../notes/notes-service.js'; import { buildSystemPrompt, type NotesInjectContext, type Movement } from './agent-loop.js'; import { DEFAULT_NOTES_INJECT } from '../config.js'; function makeMovement(): Movement { return { name: 'investigate', persona: 'investigator', instruction: 'do the thing', rules: [{ condition: 'done', next: 'plan' }], allowedTools: [], edit: false, }; } describe('buildSystemPrompt — notes inject section', () => { let tmpRoot: string; let db: Database.Database; let service: NotesService; const aliceUser = { id: 'alice', role: 'user' as const, orgIds: [] as string[], email: 'alice@example.com', name: 'Alice', avatarUrl: null, status: 'active' as const, defaultVisibility: 'private' as const, defaultVisibilityOrgId: null, }; const bobPublisher = { id: 'bob', role: 'user' as const, orgIds: [] as string[] }; beforeEach(() => { tmpRoot = mkdtempSync(join(tmpdir(), 'al-notes-test-')); db = new Database(join(tmpRoot, 'test.db')); runMigrations(db); db.prepare( `INSERT INTO users (id, email, name) VALUES ('alice','alice@example.com','Alice'),('bob','bob@example.com','Bob')` ).run(); const repo = new NotesRepository(db); service = new NotesService({ db, repo, userFolderRoot: tmpRoot, getUserOrgIds: () => [], }); }); afterEach(() => { db.close(); rmSync(tmpRoot, { recursive: true, force: true }); }); it('omits ## Subscribed Notes when user has no inject subscriptions', () => { const prompt = buildSystemPrompt( makeMovement(), 1, 5, [], undefined, null, 'alice', undefined, undefined, null, undefined, undefined, // no notesCtx ); expect(prompt).not.toContain('## Subscribed Notes'); }); it('includes ## Subscribed Notes when inject subscription exists', () => { // alice publishes a public note service.writeNote({ ownerId: 'alice', folder: 'runbooks', fileName: 'deploy.md', content: '---\nvisibility: public\n---\nDeploy checklist step 1', }); // bob subscribes to alice's note in inject mode — alice is the consumer here // Actually let's have alice subscribe to bob's note: service.writeNote({ ownerId: 'bob', folder: 'tips', fileName: 'shortcuts.md', content: '---\nvisibility: public\n---\nUseful shortcuts: Ctrl+C', }); service.upsertSubscription({ consumerUser: aliceUser as Express.User, publisherUserId: 'bob', folder: 'tips', mode: 'inject', enabled: 1, }); const notesCtx: NotesInjectContext = { service, config: DEFAULT_NOTES_INJECT, user: aliceUser, }; const prompt = buildSystemPrompt( makeMovement(), 1, 5, [], undefined, null, 'alice', undefined, undefined, null, undefined, notesCtx, ); expect(prompt).toContain('## Subscribed Notes'); expect(prompt).toContain('shortcuts.md'); expect(prompt).toContain('Useful shortcuts: Ctrl+C'); }); it('does not include section when notesCtx is provided but subscriptions are empty', () => { const notesCtx: NotesInjectContext = { service, config: DEFAULT_NOTES_INJECT, user: aliceUser, }; const prompt = buildSystemPrompt( makeMovement(), 1, 5, [], undefined, null, 'alice', undefined, undefined, null, undefined, notesCtx, ); expect(prompt).not.toContain('## Subscribed Notes'); }); });