Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license

This commit is contained in:
yilsem committed 2026-09-05 13:26:46 +03:00
commit 03634b1ca3
11340 files changed
+3442369

No files matched your search

@@ -0,0 +1,230 @@
import { beforeEach, describe, expect, it } from 'vitest'
import type { SessionInfo } from '@/types/hermes'
import { makeSessionInfo } from '../test/session-info'
import { $activeGatewayProfile } from './profile'
import {
$cronSessions,
$messagingSessions,
$selectedStoredSessionId,
$sessions,
$unreadFinishedSessionIds,
setSelectedStoredSessionId,
setSessions
} from './session'
import { clearAllSessionStates } from './session-states'
import {
$sessionSeenCounts,
$unreadFinishedMarkers,
forgetSessionUnread,
markSessionUnreadFinished
} from './session-unread'
const session = (over: Partial<SessionInfo>): SessionInfo => makeSessionInfo({ id: 'live', ...over })
function resetAll() {
clearAllSessionStates()
// Lists first: their listeners recompute the unread atom, so wiping the
// atom afterwards leaves a genuinely clean slate.
$sessions.set([])
$cronSessions.set([])
$messagingSessions.set([])
$selectedStoredSessionId.set(null)
$activeGatewayProfile.set('default')
$sessionSeenCounts.set({})
$unreadFinishedMarkers.set({})
$unreadFinishedSessionIds.set([])
}
describe('persisted unread (session-unread)', () => {
beforeEach(resetAll)
it('reconstructs the green dot from a seen watermark after a cold start', () => {
// "Restart": persisted watermark says 3 messages were seen; the freshly
// loaded list says the session now has 5 — it finished while we were away.
$sessionSeenCounts.set({ default: { s1: 3 } })
setSessions([session({ id: 's1', message_count: 5 })])
expect($unreadFinishedSessionIds.get()).toEqual(['s1'])
})
it('seeds the watermark on first sight instead of painting every row green', () => {
setSessions([session({ id: 's1', message_count: 5 })])
expect($unreadFinishedSessionIds.get()).toEqual([])
expect($sessionSeenCounts.get()).toEqual({ default: { s1: 5 } })
})
it('keeps a live-edge marker across a transient wipe (gateway/profile switch)', () => {
setSessions([session({ id: 's1', message_count: 4 })])
markSessionUnreadFinished('s1')
expect($unreadFinishedSessionIds.get()).toEqual(['s1'])
// Gateway switch: transient paint layer wiped, lists drained…
setSessions([])
$unreadFinishedSessionIds.set([])
// …then the profile's lists load again: the persisted marker repaints.
setSessions([session({ id: 's1', message_count: 4 })])
expect($unreadFinishedSessionIds.get()).toEqual(['s1'])
})
it('acks watermark + marker when the user opens the session', () => {
$sessionSeenCounts.set({ default: { s1: 3 } })
setSessions([session({ id: 's1', message_count: 5 })])
markSessionUnreadFinished('s1')
setSelectedStoredSessionId('s1')
expect($unreadFinishedSessionIds.get()).toEqual([])
expect($unreadFinishedMarkers.get()).toEqual({})
expect($sessionSeenCounts.get()).toEqual({ default: { s1: 5 } })
// A later refresh with the same count stays read.
setSessions([session({ id: 's1', message_count: 5 })])
expect($unreadFinishedSessionIds.get()).toEqual([])
})
it('tracks the selected session’s count so on-screen activity never reads as unread', () => {
$selectedStoredSessionId.set('s1')
setSessions([session({ id: 's1', message_count: 2 })])
// The turn completes while the user is looking at it.
setSessions([session({ id: 's1', message_count: 7 })])
expect($unreadFinishedSessionIds.get()).toEqual([])
expect($sessionSeenCounts.get()).toEqual({ default: { s1: 7 } })
// Navigating away must not retroactively flag it.
setSelectedStoredSessionId(null)
setSessions([session({ id: 's1', message_count: 7 })])
expect($unreadFinishedSessionIds.get()).toEqual([])
})
it('follows auto-compression id rotation via the durable lineage id', () => {
$sessionSeenCounts.set({ default: { root: 3 } })
setSessions([session({ _lineage_root_id: 'root', id: 'tip-2', message_count: 6 })])
expect($unreadFinishedSessionIds.get()).toEqual(['tip-2'])
// Opening the rotated tip acks the lineage watermark.
setSelectedStoredSessionId('tip-2')
expect($sessionSeenCounts.get()).toEqual({ default: { root: 6 } })
})
it('reconstructs unread for cron rows too', () => {
$sessionSeenCounts.set({ default: { cron1: 1 } })
$cronSessions.set([session({ id: 'cron1', message_count: 3 })])
expect($unreadFinishedSessionIds.get()).toEqual(['cron1'])
})
it('never paints messaging rows from count growth, but honors live-edge markers', () => {
// First sight seeds…
$messagingSessions.set([session({ id: 'tg1', message_count: 10 })])
// …then inbound messages bump the count: NOT "finished — unread".
$messagingSessions.set([session({ id: 'tg1', message_count: 14 })])
expect($unreadFinishedSessionIds.get()).toEqual([])
// A real background turn edge still marks it, durably.
markSessionUnreadFinished('tg1')
$unreadFinishedSessionIds.set([])
$messagingSessions.set([session({ id: 'tg1', message_count: 14 })])
expect($unreadFinishedSessionIds.get()).toEqual(['tg1'])
})
it('preserves a live-edge id whose row is not in any loaded list yet', () => {
// A brand-new session's first turn isn't flushed to the sidebar list until
// persisted — the flag must survive list refreshes in the meantime.
markSessionUnreadFinished('fresh')
setSessions([session({ id: 'other', message_count: 2 })])
expect($unreadFinishedSessionIds.get()).toContain('fresh')
})
it('keeps same-id sessions in different profiles independent', () => {
// Session ids are caller-supplied and every profile backend is its own
// namespace, so "s1" in alpha and "s1" in beta are different sessions —
// and cron/messaging lists always mix profiles into one array.
$sessionSeenCounts.set({ alpha: { s1: 3 }, beta: { s1: 5 } })
$unreadFinishedMarkers.set({ alpha: ['s1'] })
setSessions([
session({ id: 's1', message_count: 5, profile: 'beta' }),
session({ id: 's1', message_count: 5, profile: 'alpha' })
])
// Only alpha's row is past its watermark; beta's sits exactly on it.
expect($unreadFinishedSessionIds.get()).toEqual(['s1'])
expect($sessionSeenCounts.get()).toEqual({ alpha: { s1: 3 }, beta: { s1: 5 } })
// Opening beta's row (the gateway is on beta) acks beta only.
$activeGatewayProfile.set('beta')
setSelectedStoredSessionId('s1')
expect($sessionSeenCounts.get()).toEqual({ alpha: { s1: 3 }, beta: { s1: 5 } })
// alpha's marker survives an ack of beta's identically-named session.
expect($unreadFinishedMarkers.get()).toEqual({ alpha: ['s1'] })
// A later refresh must not launder alpha's gap through beta's selection.
setSessions([
session({ id: 's1', message_count: 6, profile: 'beta' }),
session({ id: 's1', message_count: 5, profile: 'alpha' })
])
expect($sessionSeenCounts.get()).toEqual({ alpha: { s1: 3 }, beta: { s1: 6 } })
expect($unreadFinishedMarkers.get()).toEqual({ alpha: ['s1'] })
})
it('files a live-edge marker with no loaded row under the active gateway profile', () => {
$activeGatewayProfile.set('work')
markSessionUnreadFinished('fresh')
expect($unreadFinishedMarkers.get()).toEqual({ work: ['fresh'] })
expect($unreadFinishedSessionIds.get()).toEqual(['fresh'])
})
it('forgets a deleted session’s persisted unread, per profile', () => {
$sessionSeenCounts.set({ alpha: { root: 3, other: 1 }, beta: { root: 9 } })
$unreadFinishedMarkers.set({ alpha: ['root', 'keep'], beta: ['root'] })
$unreadFinishedSessionIds.set(['tip-2'])
forgetSessionUnread(['tip-2', 'root', null, undefined], 'alpha')
expect($sessionSeenCounts.get()).toEqual({ alpha: { other: 1 }, beta: { root: 9 } })
expect($unreadFinishedMarkers.get()).toEqual({ alpha: ['keep'], beta: ['root'] })
expect($unreadFinishedSessionIds.get()).toEqual([])
})
it('drops an emptied profile bucket instead of persisting an empty shell', () => {
$sessionSeenCounts.set({ alpha: { s1: 3 } })
$unreadFinishedMarkers.set({ alpha: ['s1'] })
forgetSessionUnread(['s1'], 'alpha')
expect($sessionSeenCounts.get()).toEqual({})
expect($unreadFinishedMarkers.get()).toEqual({})
})
it('caps markers per profile, evicting the oldest', () => {
for (let i = 0; i < 201; i += 1) {
markSessionUnreadFinished(`s${i}`)
}
const markers = $unreadFinishedMarkers.get().default
expect(markers).toHaveLength(200)
expect(markers[0]).toBe('s1')
expect(markers.at(-1)).toBe('s200')
})
})