Resolves armed slash-command objectives from authoritative templates before dispatch Applies OpenCode argument expansion for goal metadata in UI and scheduled tasks Falls back to the raw invocation when command details are unavailable
112 lines
3.4 KiB
JavaScript
112 lines
3.4 KiB
JavaScript
import { describe, expect, it } from 'vitest';
|
|
import { computeNextRunAt, expandCommandGoalObjective, formatScheduledSessionTitle, parseScheduledCommandPrompt } from './runtime.js';
|
|
|
|
describe('scheduled-tasks runtime helpers', () => {
|
|
it('computes next daily run in timezone', () => {
|
|
const nowUtc = Date.UTC(2025, 0, 1, 8, 0, 0);
|
|
const next = computeNextRunAt({
|
|
enabled: true,
|
|
schedule: {
|
|
kind: 'daily',
|
|
times: ['09:30'],
|
|
timezone: 'UTC',
|
|
},
|
|
}, nowUtc);
|
|
|
|
expect(next).toBe(Date.UTC(2025, 0, 1, 9, 30, 0));
|
|
});
|
|
|
|
it('computes weekly next run using weekdays', () => {
|
|
// Monday 2025-01-06 10:00:00 UTC
|
|
const nowUtc = Date.UTC(2025, 0, 6, 10, 0, 0);
|
|
const next = computeNextRunAt({
|
|
enabled: true,
|
|
schedule: {
|
|
kind: 'weekly',
|
|
times: ['09:00'],
|
|
weekdays: [1, 3],
|
|
timezone: 'UTC',
|
|
},
|
|
}, nowUtc);
|
|
|
|
// Wednesday 2025-01-08 09:00:00 UTC
|
|
expect(next).toBe(Date.UTC(2025, 0, 8, 9, 0, 0));
|
|
});
|
|
|
|
it('picks nearest time from multiple daily times', () => {
|
|
const nowUtc = Date.UTC(2025, 0, 1, 9, 20, 0);
|
|
const next = computeNextRunAt({
|
|
enabled: true,
|
|
schedule: {
|
|
kind: 'daily',
|
|
times: ['09:15', '09:45', '18:00'],
|
|
timezone: 'UTC',
|
|
},
|
|
}, nowUtc);
|
|
|
|
expect(next).toBe(Date.UTC(2025, 0, 1, 9, 45, 0));
|
|
});
|
|
|
|
it('computes one-time next run for future date', () => {
|
|
const nowUtc = Date.UTC(2026, 3, 15, 10, 0, 0);
|
|
const next = computeNextRunAt({
|
|
enabled: true,
|
|
schedule: {
|
|
kind: 'once',
|
|
date: '2026-04-16',
|
|
time: '13:30',
|
|
timezone: 'UTC',
|
|
},
|
|
}, nowUtc);
|
|
|
|
expect(next).toBe(Date.UTC(2026, 3, 16, 13, 30, 0));
|
|
});
|
|
|
|
it('returns null for past one-time schedule', () => {
|
|
const nowUtc = Date.UTC(2026, 3, 16, 14, 0, 0);
|
|
const next = computeNextRunAt({
|
|
enabled: true,
|
|
schedule: {
|
|
kind: 'once',
|
|
date: '2026-04-16',
|
|
time: '13:30',
|
|
timezone: 'UTC',
|
|
},
|
|
}, nowUtc);
|
|
|
|
expect(next).toBeNull();
|
|
});
|
|
|
|
it('formats session title with timestamp suffix', () => {
|
|
const title = formatScheduledSessionTitle({
|
|
name: 'Morning Sync',
|
|
schedule: { timezone: 'UTC' },
|
|
}, Date.UTC(2025, 2, 10, 7, 5, 0));
|
|
|
|
expect(title).toBe('Morning Sync 2025-03-10 07:05');
|
|
});
|
|
|
|
it('parses slash command prompt for scheduled command mode', () => {
|
|
expect(parseScheduledCommandPrompt('/review src/components')).toEqual({
|
|
command: 'review',
|
|
arguments: 'src/components',
|
|
});
|
|
});
|
|
|
|
it('returns null when prompt is not a slash command', () => {
|
|
expect(parseScheduledCommandPrompt('Summarize open issues')).toBeNull();
|
|
expect(parseScheduledCommandPrompt('/')).toBeNull();
|
|
});
|
|
|
|
it('expands command arguments into the goal objective', () => {
|
|
expect(expandCommandGoalObjective(
|
|
'Run the issue pipeline for $ARGUMENTS. Verify $ARGUMENTS is represented by the PR.',
|
|
'LIN-123 --draft',
|
|
)).toBe('Run the issue pipeline for LIN-123 --draft. Verify LIN-123 --draft is represented by the PR.');
|
|
expect(expandCommandGoalObjective(undefined, 'LIN-123')).toBeNull();
|
|
expect(expandCommandGoalObjective('Move $1 to $2', '"src old" dist extra')).toBe('Move src old to dist extra');
|
|
expect(expandCommandGoalObjective('Review the requested scope.', 'auth module'))
|
|
.toBe('Review the requested scope.\n\nauth module');
|
|
});
|
|
});
|