mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
* fix(web): migrate chat-path attachments on scratchlist park (#1226) When an image is attached via the normal upload adapter before scratchlist mode is enabled, toggling mode swapped adapters and send() dropped the metadata — park stored text-only and cleared chips. Migrate pending chat-path files into hub scratchlist storage on send, and fail closed if non-hub paths still reach the park wrapper. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): defer chat-path cleanup until scratchlist park succeeds send() migrates before scratchlist.add; deleting the original upload there left retries pointing at a missing chat blob when park failed. Stamp migratedFromPath and clean up only after the park attempt result. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): park scratchlist before composer.send clears chips assistant-ui empties text/attachments before onNew, so return false from park could not restore retryable state and rejected cleanup deleted the migrated hub blob. Intercept park from a live snapshot; clear only after accept; releaseWithoutDelete so clearAttachments keeps parked hubs. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): lock composer while scratchlist park is in flight Disable input/send and hide chip remove during migrate+add so mid-flight edits are not wiped on success and hub blobs are not deleted out from under the accepted entry. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): do not clear composer if park snapshot changed mid-flight Compare post-await composer state to the pre-park snapshot before clearing; disable DragDropZone and scratchlist promote while parking so parent paths cannot add chips the clear would silently drop. Addresses Codex Major on #1227 (preserve post-snapshot composer changes). Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): defer migrated chat-path cleanup until park snapshot clears Return ScratchlistParkResult.beforeClear from onParkScratchlist so finalizeMigratedScratchlistParkCleanup runs only after HappyComposer confirms the composer was unchanged mid-flight. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): flush rich mentions before scratchlist park snapshot Park snapshots composer.text after flushSerializedText so session @-mention chips serialize to markdown links before scratchlist add. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): validate park snapshot before scratchlist add Split prepare/commit/abort so mid-flight composer edits abort orphan hub blobs instead of parking a duplicate. Reuse restored hub paths in prepareScratchlistParkAttachments so remounted chips do not re-upload. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): ignore scratchlist toggle hotkey while park is in flight Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
35 lines
1.1 KiB
TypeScript
35 lines
1.1 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { composerParkSnapshotUnchanged } from './HappyComposer'
|
|
|
|
describe('composerParkSnapshotUnchanged', () => {
|
|
it('returns true when text and attachment ids match', () => {
|
|
const snapshot = {
|
|
text: 'hello',
|
|
attachments: [{ id: 'a1' }, { id: 'a2' }],
|
|
}
|
|
expect(composerParkSnapshotUnchanged(snapshot, {
|
|
text: 'hello',
|
|
attachments: [{ id: 'a1' }, { id: 'a2' }],
|
|
})).toBe(true)
|
|
})
|
|
|
|
it('returns false when text or attachments changed during park', () => {
|
|
const snapshot = {
|
|
text: 'hello',
|
|
attachments: [{ id: 'a1' }],
|
|
}
|
|
expect(composerParkSnapshotUnchanged(snapshot, {
|
|
text: 'hello world',
|
|
attachments: [{ id: 'a1' }],
|
|
})).toBe(false)
|
|
expect(composerParkSnapshotUnchanged(snapshot, {
|
|
text: 'hello',
|
|
attachments: [{ id: 'a1' }, { id: 'a2' }],
|
|
})).toBe(false)
|
|
expect(composerParkSnapshotUnchanged(snapshot, {
|
|
text: 'hello',
|
|
attachments: [{ id: 'a2' }],
|
|
})).toBe(false)
|
|
})
|
|
})
|