Skip to content

Commit a144aac

Browse files
author
IM.codes
committed
Fix cron chat history sent event
1 parent b09787d commit a144aac

2 files changed

Lines changed: 36 additions & 3 deletions

File tree

src/daemon/cron-executor.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,10 @@ export async function executeCronJob(msg: CronDispatchMessage, serverLink: Serve
9696
const runtime = getTransportRuntime(name);
9797
if (runtime) {
9898
try {
99-
await runtime.send(action.command);
99+
const result = await runtime.send(action.command);
100+
if (result !== 'queued') {
101+
timelineEmitter.emit(name, 'user.message', { text: action.command, allowDuplicate: true });
102+
}
100103
} catch (err) {
101104
logger.error({ jobId, sessionName: name, err }, 'Cron: transport send failed');
102105
sendCommandResult(serverLink, {
@@ -119,6 +122,7 @@ export async function executeCronJob(msg: CronDispatchMessage, serverLink: Serve
119122
}
120123
} else {
121124
await sendKeys(name, action.command, { cwd: session.projectDir });
125+
timelineEmitter.emit(name, 'user.message', { text: action.command, allowDuplicate: true });
122126
}
123127

124128
// Capture agent response: collect assistant.text events until session goes idle

test/daemon/cron-executor.test.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ vi.mock('../../src/daemon/p2p-orchestrator.js', () => ({
2323
startP2pRun: vi.fn(),
2424
}));
2525

26-
const { timelineOn } = vi.hoisted(() => ({
26+
const { timelineOn, timelineEmit } = vi.hoisted(() => ({
2727
timelineOn: vi.fn(),
28+
timelineEmit: vi.fn(),
2829
}));
2930
vi.mock('../../src/daemon/timeline-emitter.js', () => ({
3031
timelineEmitter: {
3132
on: timelineOn,
33+
emit: timelineEmit,
3234
},
3335
}));
3436

@@ -108,6 +110,11 @@ describe('executeCronJob', () => {
108110
'review the codebase',
109111
{ cwd: '/home/user/myapp' },
110112
);
113+
expect(timelineEmit).toHaveBeenCalledWith(
114+
'deck_myapp_brain',
115+
'user.message',
116+
{ text: 'review the codebase', allowDuplicate: true },
117+
);
111118
});
112119

113120
// 2. Command to streaming session — skips (busy)
@@ -213,7 +220,7 @@ describe('executeCronJob', () => {
213220

214221
// 10. Transport session — skips busy check, calls runtime.send()
215222
it('sends command to transport session via runtime.send(), skipping busy check', async () => {
216-
const mockRuntime = { send: vi.fn().mockResolvedValue(undefined) };
223+
const mockRuntime = { send: vi.fn().mockReturnValue('sent') };
217224
(getSession as ReturnType<typeof vi.fn>).mockReturnValue(
218225
makeSession({ runtimeType: 'transport' }),
219226
);
@@ -224,6 +231,28 @@ describe('executeCronJob', () => {
224231
expect(detectStatusAsync).not.toHaveBeenCalled();
225232
expect(mockRuntime.send).toHaveBeenCalledWith('review the codebase');
226233
expect(sendKeys).not.toHaveBeenCalled();
234+
expect(timelineEmit).toHaveBeenCalledWith(
235+
'deck_myapp_brain',
236+
'user.message',
237+
{ text: 'review the codebase', allowDuplicate: true },
238+
);
239+
});
240+
241+
it('does not emit a user.message when a transport cron command is only queued', async () => {
242+
const mockRuntime = { send: vi.fn().mockReturnValue('queued') };
243+
(getSession as ReturnType<typeof vi.fn>).mockReturnValue(
244+
makeSession({ runtimeType: 'transport' }),
245+
);
246+
(getTransportRuntime as ReturnType<typeof vi.fn>).mockReturnValue(mockRuntime);
247+
248+
await executeCronJob(makeMsg(), mockServerLink);
249+
250+
expect(mockRuntime.send).toHaveBeenCalledWith('review the codebase');
251+
expect(timelineEmit).not.toHaveBeenCalledWith(
252+
'deck_myapp_brain',
253+
'user.message',
254+
expect.anything(),
255+
);
227256
});
228257

229258
// 11. Transport session with disconnected provider — skips, logs warning

0 commit comments

Comments
 (0)