mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 08:59:40 +02:00
fix(input): image paste and dictation land in the session they started in
Both read activeSessionId at the END of an async gap, so switching tabs in between sent the input to the wrong session: - An image upload inserted its paths with sendInput(), which re-reads activeSessionId after the uploads finish. It now inserts into the session the batch was uploaded to, through the same durable queue. - Voice dictation read the target when the transcript arrived and again when the send button or the compose overlay's Send was pressed. The target is now captured in start() (via _focusedPane()), the local-echo overlay is only used when that target is the active session, and a target that closed meanwhile gets a toast instead of a 404. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -143,6 +143,7 @@ function loadImageInputApp() {
|
||||
app.activeSessionId = 'session-1';
|
||||
app.showToast = vi.fn();
|
||||
app.sendInput = vi.fn(async () => {});
|
||||
app._sendInputAsync = vi.fn();
|
||||
app._normalizeImageForUpload = vi.fn(async (file) => file);
|
||||
app._uploadPasteImage = vi.fn(async (_sessionId, file: { path: string }) => file.path);
|
||||
return app as Record<string, any>;
|
||||
@@ -199,6 +200,7 @@ describe('image upload insertion policy', () => {
|
||||
|
||||
expect(Array.from(paths)).toEqual(['/tmp/first.png', '/tmp/second.png']);
|
||||
expect(app.sendInput).not.toHaveBeenCalled();
|
||||
expect(app._sendInputAsync).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('preserves terminal insertion by default', async () => {
|
||||
@@ -207,6 +209,33 @@ describe('image upload insertion policy', () => {
|
||||
const paths = await app._uploadAndInsertImages([{ path: '/tmp/legacy.png' }]);
|
||||
|
||||
expect(Array.from(paths)).toEqual(['/tmp/legacy.png']);
|
||||
expect(app.sendInput).toHaveBeenCalledWith('/tmp/legacy.png');
|
||||
// The same delivery sendInput() uses (durable queue, useMux for the POST
|
||||
// fallback), but addressed to the session the batch was uploaded to.
|
||||
expect(app._sendInputAsync).toHaveBeenCalledWith('session-1', '/tmp/legacy.png', { useMux: true });
|
||||
});
|
||||
|
||||
it('inserts into the session the upload started in, even after a tab switch mid-upload', async () => {
|
||||
const app = loadImageInputApp();
|
||||
// The user switches tabs while the upload is in flight. sendInput() re-read
|
||||
// activeSessionId after the awaits, so the paths used to land in session-2.
|
||||
app._uploadPasteImage = vi.fn(async (_sessionId, file: { path: string }) => {
|
||||
app.activeSessionId = 'session-2';
|
||||
return file.path;
|
||||
});
|
||||
|
||||
await app._uploadAndInsertImages([{ path: '/tmp/shot.png' }]);
|
||||
|
||||
expect(app._uploadPasteImage).toHaveBeenCalledWith('session-1', { path: '/tmp/shot.png' });
|
||||
expect(app._sendInputAsync).toHaveBeenCalledWith('session-1', '/tmp/shot.png', { useMux: true });
|
||||
expect(app.sendInput).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('uploads to and inserts into an explicitly named session', async () => {
|
||||
const app = loadImageInputApp();
|
||||
|
||||
await app._uploadAndInsertImages([{ path: '/tmp/pane-b.png' }], { sessionId: 'session-b' });
|
||||
|
||||
expect(app._uploadPasteImage).toHaveBeenCalledWith('session-b', { path: '/tmp/pane-b.png' });
|
||||
expect(app._sendInputAsync).toHaveBeenCalledWith('session-b', '/tmp/pane-b.png', { useMux: true });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user