94 lines
3 KiB
TypeScript
94 lines
3 KiB
TypeScript
import * as path from 'path';
|
|
import { describe, expect, it } from 'vitest';
|
|
|
|
import {
|
|
buildTeamLogWatchSessionIds,
|
|
classifyLogSourceWatcherEvent,
|
|
extractRuntimeSessionIds,
|
|
normalizeLogSourceSessionId,
|
|
} from '../../../../src/main/services/team/teamLogSourceWatchScope';
|
|
|
|
describe('teamLogSourceWatchScope', () => {
|
|
it('builds a bounded confirmed session scope with lead, runtime ids, and newest history first', () => {
|
|
const ids = buildTeamLogWatchSessionIds({
|
|
configLeadSessionId: 'lead-session',
|
|
launchLeadSessionId: 'lead-session',
|
|
launchRuntimeSessionIds: ['runtime-bob'],
|
|
sessionHistory: ['old-session', 'recent-session', 'lead-session'],
|
|
});
|
|
|
|
expect(ids).toEqual(['lead-session', 'runtime-bob', 'recent-session', 'old-session']);
|
|
});
|
|
|
|
it('normalizes session ids defensively', () => {
|
|
expect(normalizeLogSourceSessionId(' valid_id-1 ')).toBe('valid_id-1');
|
|
expect(normalizeLogSourceSessionId('')).toBeNull();
|
|
expect(normalizeLogSourceSessionId('../escape')).toBeNull();
|
|
expect(normalizeLogSourceSessionId('with/slash')).toBeNull();
|
|
});
|
|
|
|
it('extracts runtime session ids from launch members that can still write early logs', () => {
|
|
const ids = extractRuntimeSessionIds({
|
|
members: {
|
|
pending: {
|
|
launchState: 'runtime_pending_bootstrap',
|
|
runtimeSessionId: 'runtime-pending',
|
|
hardFailure: false,
|
|
},
|
|
failed: {
|
|
launchState: 'failed_to_start',
|
|
runtimeSessionId: 'runtime-failed',
|
|
hardFailure: true,
|
|
},
|
|
},
|
|
} as never);
|
|
|
|
expect(ids).toEqual(['runtime-pending']);
|
|
});
|
|
|
|
it('classifies unknown, pending, scoped, and ignored watcher events', () => {
|
|
const projectDir = '/tmp/project';
|
|
const scopedSessionIds = new Set(['lead-session']);
|
|
const pendingUnknownSessionIds = new Set(['new-runtime']);
|
|
|
|
expect(
|
|
classifyLogSourceWatcherEvent({
|
|
projectDir,
|
|
changedPath: path.join(projectDir, 'old-session.jsonl'),
|
|
eventName: 'change',
|
|
scopedSessionIds,
|
|
pendingUnknownSessionIds,
|
|
})
|
|
).toEqual({ kind: 'ignore' });
|
|
|
|
expect(
|
|
classifyLogSourceWatcherEvent({
|
|
projectDir,
|
|
changedPath: path.join(projectDir, 'new-runtime.jsonl'),
|
|
eventName: 'change',
|
|
scopedSessionIds,
|
|
pendingUnknownSessionIds,
|
|
})
|
|
).toEqual({ kind: 'context-refresh', candidateSessionId: 'new-runtime' });
|
|
|
|
expect(
|
|
classifyLogSourceWatcherEvent({
|
|
projectDir,
|
|
changedPath: path.join(projectDir, 'lead-session', 'subagents', 'agent-worker.jsonl'),
|
|
eventName: 'change',
|
|
scopedSessionIds,
|
|
pendingUnknownSessionIds,
|
|
})
|
|
).toEqual({ kind: 'scoped-recompute' });
|
|
|
|
expect(
|
|
classifyLogSourceWatcherEvent({
|
|
projectDir,
|
|
changedPath: path.join(projectDir, 'lead-session', 'subagents', 'agent-acompact-x.jsonl'),
|
|
eventName: 'change',
|
|
scopedSessionIds,
|
|
pendingUnknownSessionIds,
|
|
})
|
|
).toEqual({ kind: 'ignore' });
|
|
});
|
|
});
|