fix(web): deduplicate subagent navigation
This commit is contained in:
@@ -42,7 +42,7 @@ describe('sessions.list cold merge', () => {
|
||||
utimesSync(logPath, 5000, 5000) // mtime 5_000_000 ms — newer than every createdAt below
|
||||
const metas = [
|
||||
header('session-a', 1000),
|
||||
header('session-b', 2000, { parentSession: sid('session-parent') }),
|
||||
header('session-b', 2000, { parentSession: sid('session-parent'), origin: 'subagent' }),
|
||||
header('session-c', 1500),
|
||||
]
|
||||
// Structural fake of the persistence face list() consumes: list + locate.
|
||||
@@ -74,6 +74,7 @@ describe('sessions.list cold merge', () => {
|
||||
expect(a?.parentSessionId).toBeUndefined()
|
||||
expect(b?.updatedAt).toBe(2000)
|
||||
expect(b?.parentSessionId).toBe('session-parent')
|
||||
expect(b?.origin).toBe('subagent')
|
||||
expect(c?.updatedAt).toBe(1500)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -364,6 +364,36 @@ describe('session creation and Workspace membership', () => {
|
||||
})
|
||||
|
||||
describe('Host Workspace increments', () => {
|
||||
it('projects subagent origin in attached summaries and creation increments', async () => {
|
||||
const { api, ctx } = await harness()
|
||||
const abort = new AbortController()
|
||||
const stream: AsyncIterator<RpcRequest<HostFrame>> =
|
||||
api.events.host(request({}), abort.signal)[Symbol.asyncIterator]()
|
||||
const pending = nextHostFrame(stream)
|
||||
const childId = SessionId('session-subagent-child')
|
||||
|
||||
ctx.sessions.create(childId, {
|
||||
meta: {
|
||||
cwd: '/tmp',
|
||||
parentSession: SessionId('session-parent'),
|
||||
origin: 'subagent',
|
||||
},
|
||||
})
|
||||
|
||||
expect(await pending).toMatchObject({
|
||||
payload: {
|
||||
type: 'host/session-added',
|
||||
sessionId: childId,
|
||||
parentSessionId: 'session-parent',
|
||||
origin: 'subagent',
|
||||
},
|
||||
})
|
||||
expect(expectOk(await api.sessions.list(request({}))).items).toContainEqual(
|
||||
expect.objectContaining({ sessionId: childId, origin: 'subagent' }),
|
||||
)
|
||||
abort.abort()
|
||||
})
|
||||
|
||||
it('streams committed Workspace and Session increments after empty baselines', async () => {
|
||||
const { api } = await harness()
|
||||
expect(expectOk(await api.workspace.list(request({}))).items).toEqual([])
|
||||
|
||||
@@ -141,7 +141,13 @@ describe('sessions domain schemas', () => {
|
||||
expect(sessionIdSchema.parse('s1')).toBe('s1')
|
||||
expect(() => sessionIdSchema.parse('')).toThrow()
|
||||
expect(sessionSummarySchema.parse({ sessionId: 's1', updatedAt: 1, running: false, blank: true })).toMatchObject({ sessionId: 's1', blank: true })
|
||||
expect(sessionSummarySchema.parse({ sessionId: 's1', updatedAt: 1, running: true, blank: false, parentSessionId: 'p', cwd: '/x' }).cwd).toBe('/x')
|
||||
expect(sessionSummarySchema.parse({
|
||||
sessionId: 's1', updatedAt: 1, running: true, blank: false,
|
||||
parentSessionId: 'p', origin: 'subagent', cwd: '/x',
|
||||
})).toMatchObject({ origin: 'subagent', cwd: '/x' })
|
||||
expect(() => sessionSummarySchema.parse({
|
||||
sessionId: 's1', updatedAt: 1, running: false, blank: false, origin: 'fork',
|
||||
})).toThrow()
|
||||
// blank is mandatory: a summary without it fails the parse.
|
||||
expect(() => sessionSummarySchema.parse({ sessionId: 's1', updatedAt: 1, running: false })).toThrow()
|
||||
const event = sessionEventSchema.parse({
|
||||
@@ -498,7 +504,7 @@ describe('events frame schemas', () => {
|
||||
|
||||
it('accepts every host frame branch', () => {
|
||||
const frames = [
|
||||
{ type: 'host/session-added', sessionId: 's', blank: true, parentSessionId: 'p' },
|
||||
{ type: 'host/session-added', sessionId: 's', blank: true, parentSessionId: 'p', origin: 'subagent' },
|
||||
{ type: 'host/session-added', sessionId: 's', blank: true },
|
||||
{ type: 'host/session-removed', sessionId: 's' },
|
||||
{ type: 'host/session-status', sessionId: 's', running: true },
|
||||
@@ -512,6 +518,9 @@ describe('events frame schemas', () => {
|
||||
{ type: 'stream/error', error: { code: 'internal', message: 'm', details: {} } },
|
||||
]
|
||||
for (const frame of frames) expect(hostFrameSchema.parse(frame)).toMatchObject({ type: frame.type })
|
||||
expect(() => hostFrameSchema.parse({
|
||||
type: 'host/session-added', sessionId: 's', blank: true, origin: 'fork',
|
||||
})).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user