Sessions: account a restored Session to its Workspace
Ensure() only registered a Workspace when the Session was new, so Sessions restored from disk never entered the Workspace record and stayed invisible in the panel. Always create (idempotent) and attach an unaccounted Session; warn on attach failure. Tests gain a shared Workspace fixture.
This commit is contained in:
Vendored
+25
-2
@@ -85,6 +85,28 @@ export function jobRegistry(owner: (sessionId: string) => FakeAgent | undefined
|
||||
run: (owner: string, label?: string) => { const id = `bash-${jobs.size + 1}`; jobs.set(id, { id, owner, status: 'running', label }); return id } }
|
||||
}
|
||||
|
||||
/**
|
||||
* DSH's Workspace registry as the Sessions use it: one Workspace per directory, which `create` resolves idempotently by path
|
||||
* and which accounts the Sessions a launch attaches. `attach` records an attachment per Session so a test can assert that a
|
||||
* Session restored without its Workspace registration is put back into one.
|
||||
*/
|
||||
export function workspaceRegistry() {
|
||||
const byPath = new Map<string, { id: string; path: string; sessionIds: string[]; attachSession: ReturnType<typeof vi.fn> }>()
|
||||
const create = vi.fn(async (cwd: string) => {
|
||||
const existing = byPath.get(cwd)
|
||||
if (existing) return existing
|
||||
const workspace = {
|
||||
id: `workspace-${byPath.size + 1}`,
|
||||
path: cwd,
|
||||
sessionIds: [] as string[],
|
||||
attachSession: vi.fn(async (sessionId: string) => { if (!workspace.sessionIds.includes(sessionId)) workspace.sessionIds.push(sessionId) }),
|
||||
}
|
||||
byPath.set(cwd, workspace)
|
||||
return workspace
|
||||
})
|
||||
return { service: { create }, create, byPath }
|
||||
}
|
||||
|
||||
/**
|
||||
* DSH's subagents as the Executor uses them. `spawn` starts a child of a Session, an agent while it lives, which a drain of
|
||||
* the Session's descendants refuses from then on; `settle` ends one, whose end wakes its idle parent or steers a running one
|
||||
@@ -238,8 +260,9 @@ export async function startRuntime(seed?: (store: Store) => void) {
|
||||
const webServer = { host: '127.0.0.1', port: 3082, register: (route: { handler: HttpHandler }) => { http = route.handler; return () => {} } }
|
||||
const jobs = jobRegistry(id => agents.get(id))
|
||||
const subagents = subagentRuntime(agents)
|
||||
const workspaces = workspaceRegistry()
|
||||
const services = { agents, llm: { resolveCallConfig: vi.fn(async (value: unknown) => value) }, sessionController: controller,
|
||||
sessionPersistence: persistence, workspaceRegistry: { create: async (cwd: string) => ({ id: cwd }) }, permissionPresets: { set: () => {} }, subprocess, webServer,
|
||||
sessionPersistence: persistence, workspaceRegistry: workspaces.service, permissionPresets: { set: () => {} }, subprocess, webServer,
|
||||
jobs: jobs.service, subagents: subagents.service }
|
||||
const ctx = new Context()
|
||||
for (const [name, service] of Object.entries(services)) ctx.reflect.provide(name, service)
|
||||
@@ -294,6 +317,6 @@ export async function startRuntime(seed?: (store: Store) => void) {
|
||||
/** A step of the worker claims what waits for it, and is cut off before the Session took it. */
|
||||
const claim = (sessionId: string) => { claims.get(sessionId)!() }
|
||||
return { runtime, ctx, directory, agents, tools, deliveries, relays, candidates, runTool, route, acceptedTicket, api, controller, subprocess, hooks, resolveDefault, stop,
|
||||
jobs, subagents, step, claim }
|
||||
jobs, subagents, workspaces, step, claim }
|
||||
}
|
||||
export type Host = Awaited<ReturnType<typeof startRuntime>>
|
||||
|
||||
Reference in New Issue
Block a user