Buckets:
| import { Binary } from "@opencode-ai/core/util/binary" | |
| import { produce, reconcile, type SetStoreFunction, type Store } from "solid-js/store" | |
| import type { | |
| Message, | |
| Part, | |
| PermissionRequest, | |
| Project, | |
| QuestionRequest, | |
| Session, | |
| SessionStatus, | |
| SnapshotFileDiff, | |
| Todo, | |
| } from "@opencode-ai/sdk/v2/client" | |
| import type { State, VcsCache } from "./types" | |
| import { trimSessions } from "./session-trim" | |
| import { dropSessionCaches } from "./session-cache" | |
| import { diffs as list, message as clean } from "@/utils/diffs" | |
| const SKIP_PARTS = new Set(["patch", "step-start", "step-finish"]) | |
| export function applyGlobalEvent(input: { | |
| event: { type: string; properties?: unknown } | |
| project: Project[] | |
| setGlobalProject: (next: Project[] | ((draft: Project[]) => Project[])) => void | |
| refresh: () => void | |
| }) { | |
| if (input.event.type === "global.disposed" || input.event.type === "server.connected") { | |
| input.refresh() | |
| return | |
| } | |
| if (input.event.type !== "project.updated") return | |
| const properties = input.event.properties as Project | |
| const result = Binary.search(input.project, properties.id, (s) => s.id) | |
| if (result.found) { | |
| input.setGlobalProject( | |
| produce((draft) => { | |
| draft[result.index] = { ...draft[result.index], ...properties } | |
| }), | |
| ) | |
| return | |
| } | |
| input.setGlobalProject( | |
| produce((draft) => { | |
| draft.splice(result.index, 0, properties) | |
| }), | |
| ) | |
| } | |
| function cleanupSessionCaches( | |
| setStore: SetStoreFunction<State>, | |
| sessionID: string, | |
| setSessionTodo?: (sessionID: string, todos: Todo[] | undefined) => void, | |
| ) { | |
| if (!sessionID) return | |
| setSessionTodo?.(sessionID, undefined) | |
| setStore( | |
| produce((draft) => { | |
| dropSessionCaches(draft, [sessionID]) | |
| }), | |
| ) | |
| } | |
| export function cleanupDroppedSessionCaches( | |
| store: Store<State>, | |
| setStore: SetStoreFunction<State>, | |
| next: Session[], | |
| setSessionTodo?: (sessionID: string, todos: Todo[] | undefined) => void, | |
| ) { | |
| const keep = new Set(next.map((item) => item.id)) | |
| const stale = [ | |
| ...Object.keys(store.message), | |
| ...Object.keys(store.session_diff), | |
| ...Object.keys(store.todo), | |
| ...Object.keys(store.permission), | |
| ...Object.keys(store.question), | |
| ...Object.keys(store.session_status), | |
| ...Object.values(store.part) | |
| .map((parts) => parts?.find((part) => !!part?.sessionID)?.sessionID) | |
| .filter((sessionID): sessionID is string => !!sessionID), | |
| ].filter((sessionID, index, list) => !keep.has(sessionID) && list.indexOf(sessionID) === index) | |
| if (stale.length === 0) return | |
| for (const sessionID of stale) { | |
| setSessionTodo?.(sessionID, undefined) | |
| } | |
| setStore( | |
| produce((draft) => { | |
| dropSessionCaches(draft, stale) | |
| }), | |
| ) | |
| } | |
| export function applyDirectoryEvent(input: { | |
| event: { type: string; properties?: unknown } | |
| store: Store<State> | |
| setStore: SetStoreFunction<State> | |
| push: (directory: string) => void | |
| directory: string | |
| loadLsp: () => void | |
| vcsCache?: VcsCache | |
| setSessionTodo?: (sessionID: string, todos: Todo[] | undefined) => void | |
| retainedLimit?: number | |
| }) { | |
| const event = input.event | |
| const limit = Math.max(input.store.limit, input.retainedLimit ?? 0) | |
| switch (event.type) { | |
| case "server.instance.disposed": { | |
| input.push(input.directory) | |
| return | |
| } | |
| case "session.created": { | |
| const info = (event.properties as { info: Session }).info | |
| const result = Binary.search(input.store.session, info.id, (s) => s.id) | |
| if (result.found) { | |
| input.setStore("session", result.index, reconcile(info)) | |
| break | |
| } | |
| const next = input.store.session.slice() | |
| next.splice(result.index, 0, info) | |
| const trimmed = trimSessions(next, { limit, permission: input.store.permission }) | |
| input.setStore("session", reconcile(trimmed, { key: "id" })) | |
| cleanupDroppedSessionCaches(input.store, input.setStore, trimmed, input.setSessionTodo) | |
| if (!info.parentID) input.setStore("sessionTotal", (value) => value + 1) | |
| break | |
| } | |
| case "session.updated": { | |
| const info = (event.properties as { info: Session }).info | |
| const result = Binary.search(input.store.session, info.id, (s) => s.id) | |
| if (info.time.archived) { | |
| if (input.store.session[result.index]!.time.archived === info.time.archived) break | |
| if (result.found) { | |
| input.setStore( | |
| "session", | |
| produce((draft) => { | |
| draft.splice(result.index, 1) | |
| }), | |
| ) | |
| } | |
| cleanupSessionCaches(input.setStore, info.id, input.setSessionTodo) | |
| if (info.parentID) break | |
| input.setStore("sessionTotal", (value) => Math.max(0, value - 1)) | |
| break | |
| } | |
| if (result.found) { | |
| input.setStore("session", result.index, reconcile(info)) | |
| break | |
| } | |
| const next = input.store.session.slice() | |
| next.splice(result.index, 0, info) | |
| const trimmed = trimSessions(next, { limit, permission: input.store.permission }) | |
| input.setStore("session", reconcile(trimmed, { key: "id" })) | |
| cleanupDroppedSessionCaches(input.store, input.setStore, trimmed, input.setSessionTodo) | |
| break | |
| } | |
| case "session.deleted": { | |
| const info = (event.properties as { info: Session }).info | |
| const result = Binary.search(input.store.session, info.id, (s) => s.id) | |
| if (result.found) { | |
| input.setStore( | |
| "session", | |
| produce((draft) => { | |
| draft.splice(result.index, 1) | |
| }), | |
| ) | |
| } | |
| cleanupSessionCaches(input.setStore, info.id, input.setSessionTodo) | |
| if (info.parentID) break | |
| input.setStore("sessionTotal", (value) => Math.max(0, value - 1)) | |
| break | |
| } | |
| case "session.diff": { | |
| const props = event.properties as { sessionID: string; diff: SnapshotFileDiff[] } | |
| input.setStore("session_diff", props.sessionID, reconcile(list(props.diff), { key: "file" })) | |
| break | |
| } | |
| case "todo.updated": { | |
| const props = event.properties as { sessionID: string; todos: Todo[] } | |
| input.setStore("todo", props.sessionID, reconcile(props.todos, { key: "id" })) | |
| input.setSessionTodo?.(props.sessionID, props.todos) | |
| break | |
| } | |
| case "session.status": { | |
| const props = event.properties as { sessionID: string; status: SessionStatus } | |
| input.setStore("session_status", props.sessionID, reconcile(props.status)) | |
| break | |
| } | |
| case "message.updated": { | |
| const info = clean((event.properties as { info: Message }).info) | |
| const messages = input.store.message[info.sessionID] | |
| if (!messages) { | |
| input.setStore("message", info.sessionID, [info]) | |
| break | |
| } | |
| const result = Binary.search(messages, info.id, (m) => m.id) | |
| if (result.found) { | |
| input.setStore("message", info.sessionID, result.index, reconcile(info)) | |
| break | |
| } | |
| input.setStore( | |
| "message", | |
| info.sessionID, | |
| produce((draft) => { | |
| draft.splice(result.index, 0, info) | |
| }), | |
| ) | |
| break | |
| } | |
| case "message.removed": { | |
| const props = event.properties as { sessionID: string; messageID: string } | |
| input.setStore( | |
| produce((draft) => { | |
| const messages = draft.message[props.sessionID] | |
| if (messages) { | |
| const result = Binary.search(messages, props.messageID, (m) => m.id) | |
| if (result.found) messages.splice(result.index, 1) | |
| } | |
| const parts = draft.part[props.messageID] | |
| if (parts) { | |
| for (const part of parts) { | |
| delete draft.part_text_accum_delta[part.id] | |
| } | |
| } | |
| delete draft.part[props.messageID] | |
| }), | |
| ) | |
| break | |
| } | |
| case "message.part.updated": { | |
| const part = (event.properties as { part: Part }).part | |
| if (SKIP_PARTS.has(part.type)) break | |
| input.setStore( | |
| produce((draft) => { | |
| delete draft.part_text_accum_delta[part.id] | |
| }), | |
| ) | |
| const parts = input.store.part[part.messageID] | |
| if (!parts) { | |
| input.setStore("part", part.messageID, [part]) | |
| break | |
| } | |
| const result = Binary.search(parts, part.id, (p) => p.id) | |
| if (result.found) { | |
| input.setStore("part", part.messageID, result.index, reconcile(part)) | |
| break | |
| } | |
| input.setStore( | |
| "part", | |
| part.messageID, | |
| produce((draft) => { | |
| draft.splice(result.index, 0, part) | |
| }), | |
| ) | |
| break | |
| } | |
| case "message.part.removed": { | |
| const props = event.properties as { messageID: string; partID: string } | |
| input.setStore( | |
| produce((draft) => { | |
| delete draft.part_text_accum_delta[props.partID] | |
| }), | |
| ) | |
| const parts = input.store.part[props.messageID] | |
| if (!parts) break | |
| const result = Binary.search(parts, props.partID, (p) => p.id) | |
| if (result.found) { | |
| input.setStore( | |
| produce((draft) => { | |
| const list = draft.part[props.messageID] | |
| if (!list) return | |
| const next = Binary.search(list, props.partID, (p) => p.id) | |
| if (!next.found) return | |
| list.splice(next.index, 1) | |
| if (list.length === 0) delete draft.part[props.messageID] | |
| }), | |
| ) | |
| } | |
| break | |
| } | |
| case "message.part.delta": { | |
| const props = event.properties as { messageID: string; partID: string; field: string; delta: string } | |
| const parts = input.store.part[props.messageID] | |
| if (!parts) break | |
| const result = Binary.search(parts, props.partID, (p) => p.id) | |
| if (!result.found) break | |
| input.setStore("part_text_accum_delta", props.partID, (existing) => (existing ?? "") + props.delta) | |
| input.setStore( | |
| "part", | |
| props.messageID, | |
| produce((draft) => { | |
| const part = draft[result.index] | |
| const field = props.field as keyof typeof part | |
| const existing = part[field] as string | undefined | |
| ;(part[field] as string) = (existing ?? "") + props.delta | |
| }), | |
| ) | |
| break | |
| } | |
| case "vcs.branch.updated": { | |
| const props = event.properties as { branch?: string } | |
| if (input.store.vcs?.branch === props.branch) break | |
| const next = { ...input.store.vcs, branch: props.branch } | |
| input.setStore("vcs", next) | |
| if (input.vcsCache) input.vcsCache.setStore("value", next) | |
| break | |
| } | |
| case "permission.asked": { | |
| const permission = event.properties as PermissionRequest | |
| const permissions = input.store.permission[permission.sessionID] | |
| if (!permissions) { | |
| input.setStore("permission", permission.sessionID, [permission]) | |
| break | |
| } | |
| const result = Binary.search(permissions, permission.id, (p) => p.id) | |
| if (result.found) { | |
| input.setStore("permission", permission.sessionID, result.index, reconcile(permission)) | |
| break | |
| } | |
| input.setStore( | |
| "permission", | |
| permission.sessionID, | |
| produce((draft) => { | |
| draft.splice(result.index, 0, permission) | |
| }), | |
| ) | |
| break | |
| } | |
| case "permission.replied": { | |
| const props = event.properties as { sessionID: string; requestID: string } | |
| const permissions = input.store.permission[props.sessionID] | |
| if (!permissions) break | |
| const result = Binary.search(permissions, props.requestID, (p) => p.id) | |
| if (!result.found) break | |
| input.setStore( | |
| "permission", | |
| props.sessionID, | |
| produce((draft) => { | |
| draft.splice(result.index, 1) | |
| }), | |
| ) | |
| break | |
| } | |
| case "question.asked": { | |
| const question = event.properties as QuestionRequest | |
| const questions = input.store.question[question.sessionID] | |
| if (!questions) { | |
| input.setStore("question", question.sessionID, [question]) | |
| break | |
| } | |
| const result = Binary.search(questions, question.id, (q) => q.id) | |
| if (result.found) { | |
| input.setStore("question", question.sessionID, result.index, reconcile(question)) | |
| break | |
| } | |
| input.setStore( | |
| "question", | |
| question.sessionID, | |
| produce((draft) => { | |
| draft.splice(result.index, 0, question) | |
| }), | |
| ) | |
| break | |
| } | |
| case "question.replied": | |
| case "question.rejected": { | |
| const props = event.properties as { sessionID: string; requestID: string } | |
| const questions = input.store.question[props.sessionID] | |
| if (!questions) break | |
| const result = Binary.search(questions, props.requestID, (q) => q.id) | |
| if (!result.found) break | |
| input.setStore( | |
| "question", | |
| props.sessionID, | |
| produce((draft) => { | |
| draft.splice(result.index, 1) | |
| }), | |
| ) | |
| break | |
| } | |
| case "lsp.updated": { | |
| input.loadLsp() | |
| break | |
| } | |
| } | |
| } | |
Xet Storage Details
- Size:
- 12.9 kB
- Xet hash:
- 7f85ad0846af314db5fcbd5e9050e7fe2fba22a9484e36b925994051a500ebb6
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.