fix(ui): preserve upstream behavior after performance rebase
This commit is contained in:
@@ -65,7 +65,7 @@ The composer compares normalized attachment MIME types with the selected model's
|
||||
|
||||
### Layout-mounted session-list lifecycle
|
||||
|
||||
`MainLayout` and `VSCodeLayout` each call `useSessionListSync({ isVSCode })` directly and unconditionally, outside Sidebar visibility, responsive, editor, settings, and compact-view branches. The hook selects the real topology inputs, publishes complete directory bootstrap demand through `ChildStoreManager`, refreshes the global list once per layout mount, refreshes topology additions (including all VS Code directories on its first mount), coalesces OpenChamber control events for 500ms, and supplies a memoized complete global active+archived input to authoritative cleanup. MainLayout includes available worktrees; VS Code intentionally excludes them. Sidebar-local `session-created` worktree discovery is separate and full-app-only.
|
||||
`MainLayout` and `VSCodeLayout` each call `useSessionListSync({ isVSCode })` directly and unconditionally, outside Sidebar visibility, responsive, editor, settings, and compact-view branches. The hook selects the real topology inputs, publishes complete directory bootstrap demand through `ChildStoreManager`, refreshes topology additions (including all VS Code directories on its first mount), coalesces OpenChamber control events for 500ms, and supplies a memoized complete global active+archived input to authoritative cleanup. The root-level global poller owns the initial global refresh. MainLayout includes available worktrees; VS Code intentionally excludes them. Sidebar-local `session-created` worktree discovery is separate and full-app-only.
|
||||
|
||||
### Directory bootstrap scheduling
|
||||
|
||||
|
||||
@@ -27,6 +27,18 @@ describe("upsertSessionRecord", () => {
|
||||
expect(result[1]).toBe(current[1])
|
||||
})
|
||||
|
||||
test("replaces a same-ID record when an unlisted semantic field changes", () => {
|
||||
const current = [session("a")]
|
||||
// SAFETY: The runtime SDK payload may contain an additive field before the local Session type is updated.
|
||||
const incoming = {
|
||||
...session("a"),
|
||||
// SDK records can gain fields independently of this synchronization boundary.
|
||||
customField: "changed",
|
||||
} as Session
|
||||
|
||||
expect(upsertSessionRecord(current, incoming)).not.toBe(current)
|
||||
})
|
||||
|
||||
const changes: Array<[string, Partial<Session>, Partial<Session>]> = [
|
||||
["scalars", { workspaceID: "one", path: "a", parentID: "p", cost: 1, agent: "a" }, { workspaceID: "two", path: "b", parentID: "q", cost: 2, agent: "b" }],
|
||||
["tokens", { tokens: { input: 1, output: 2, reasoning: 3, cache: { read: 4, write: 5 } } }, { tokens: { input: 1, output: 2, reasoning: 3, cache: { read: 4, write: 6 } } }],
|
||||
|
||||
@@ -1,83 +1,8 @@
|
||||
import type { PermissionRuleset, Session, SnapshotFileDiff } from "@opencode-ai/sdk/v2"
|
||||
import type { Session } from "@opencode-ai/sdk/v2"
|
||||
import { Binary } from "./binary"
|
||||
|
||||
function areMetadataEqual(left: Session["metadata"], right: Session["metadata"]): boolean {
|
||||
return JSON.stringify(left ?? null) === JSON.stringify(right ?? null)
|
||||
}
|
||||
|
||||
function optionalEqual<T>(
|
||||
left: T | undefined,
|
||||
right: T | undefined,
|
||||
equal: (left: T, right: T) => boolean,
|
||||
): boolean {
|
||||
return left === right || (left !== undefined && right !== undefined && equal(left, right))
|
||||
}
|
||||
|
||||
const diffsEqual = (left: SnapshotFileDiff[], right: SnapshotFileDiff[]) => (
|
||||
left.length === right.length
|
||||
&& left.every((item, index) => {
|
||||
const candidate = right[index]
|
||||
return item.file === candidate.file
|
||||
&& item.patch === candidate.patch
|
||||
&& item.additions === candidate.additions
|
||||
&& item.deletions === candidate.deletions
|
||||
&& item.status === candidate.status
|
||||
})
|
||||
)
|
||||
|
||||
const permissionsEqual = (left: PermissionRuleset, right: PermissionRuleset) => (
|
||||
left.length === right.length
|
||||
&& left.every((item, index) => {
|
||||
const candidate = right[index]
|
||||
return item.permission === candidate.permission
|
||||
&& item.pattern === candidate.pattern
|
||||
&& item.action === candidate.action
|
||||
})
|
||||
)
|
||||
|
||||
function areSessionsEqual(left: Session, right: Session): boolean {
|
||||
return left.id === right.id
|
||||
&& left.slug === right.slug
|
||||
&& left.projectID === right.projectID
|
||||
&& left.workspaceID === right.workspaceID
|
||||
&& left.directory === right.directory
|
||||
&& left.path === right.path
|
||||
&& left.parentID === right.parentID
|
||||
&& left.cost === right.cost
|
||||
&& left.title === right.title
|
||||
&& left.agent === right.agent
|
||||
&& left.version === right.version
|
||||
&& areMetadataEqual(left.metadata, right.metadata)
|
||||
&& optionalEqual(left.summary, right.summary, (a, b) => (
|
||||
a.additions === b.additions
|
||||
&& a.deletions === b.deletions
|
||||
&& a.files === b.files
|
||||
&& optionalEqual(a.diffs, b.diffs, diffsEqual)
|
||||
))
|
||||
&& optionalEqual(left.tokens, right.tokens, (a, b) => (
|
||||
a.input === b.input
|
||||
&& a.output === b.output
|
||||
&& a.reasoning === b.reasoning
|
||||
&& a.cache.read === b.cache.read
|
||||
&& a.cache.write === b.cache.write
|
||||
))
|
||||
&& optionalEqual(left.share, right.share, (a, b) => a.url === b.url)
|
||||
&& optionalEqual(left.model, right.model, (a, b) => (
|
||||
a.id === b.id
|
||||
&& a.providerID === b.providerID
|
||||
&& a.variant === b.variant
|
||||
))
|
||||
&& left.time.created === right.time.created
|
||||
&& left.time.updated === right.time.updated
|
||||
&& left.time.compacting === right.time.compacting
|
||||
&& left.time.archived === right.time.archived
|
||||
&& optionalEqual(left.permission, right.permission, permissionsEqual)
|
||||
&& optionalEqual(left.revert, right.revert, (a, b) => (
|
||||
a.messageID === b.messageID
|
||||
&& a.partID === b.partID
|
||||
&& a.snapshot === b.snapshot
|
||||
&& a.diff === b.diff
|
||||
))
|
||||
return JSON.stringify(left) === JSON.stringify(right)
|
||||
}
|
||||
|
||||
export function upsertSessionRecord(current: Session[], incoming: Session): Session[] {
|
||||
|
||||
Reference in New Issue
Block a user