mirror of
https://github.com/stablyai/orca.git
synced 2026-11-04 19:17:28 +00:00
* feat(connectors): connector seam lifecycle, conversation links and start behind experimentalConnectors (B2b-1) * feat(connectors): connector follow-ups, held while the agent asks, behind experimentalConnectors (B2b-2) * feat(agent-write): opt-in launch cancel, approval wait and binding fence on the shared writer executeAgentLaunch takes an optional signal; sendTerminalAgentPrompt (and sendAgentTurn) take optional onPermission: 'wait' and expectedBinding. No existing caller sets them, so every current path is unchanged. * fix(agent-write): keep the default writer path main's; fence cancel and real submit boundary Only opted-in writes take the submit layer, so default timing and the leaf re-read are unchanged. Cancellation is rechecked before a structured-refusal terminal fallback, and an opted-in launch learns Enter from an onSubmitWritten callback at the write itself, OMP's combined frame included. * fix(connectors): pass the seam's signal to the launch, read links from each host's rows, and keep delivery ids on orchestration's durable receipts (B2b-1) * fix(agent-launch): a cancel after a failed startup spawn recovers the created workspace * fix(connectors): keep an unknown receipt once the launch published, and restore local-only metadata ownership (B2b-1) * fix(connectors): settle a lane when its process is lost; removal stays host-qualified; folder delete announces removal * fix(plugins): keep folder removals out of public worktree events * fix(connectors): a launch admits its process for the lane, so queued sends never adopt a successor * fix(connectors): classify connector RPCs as host-owned; CLI start output claims a start only when definite
76 lines
2.8 KiB
TypeScript
76 lines
2.8 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
import { RuntimeProjectGroupController } from './runtime-project-group-controller'
|
|
import type { FolderWorkspace } from '../../shared/folder-workspace-types'
|
|
|
|
const workspace = {
|
|
id: 'ws-1',
|
|
projectGroupId: 'group-1',
|
|
folderPath: '/tmp/ws'
|
|
} as FolderWorkspace
|
|
|
|
function createController(
|
|
resolveFolderConnectionId: (workspace: FolderWorkspace) => string | null
|
|
) {
|
|
const removeFolderWorkspace = vi.fn(() => true)
|
|
const teardownFolderWorkspacePtys = vi.fn(async () => undefined)
|
|
const cleanupRemovedFolderWorkspaceState = vi.fn()
|
|
const notifyReposChanged = vi.fn()
|
|
const emitWorktreeLifecycle = vi.fn()
|
|
const controller = new RuntimeProjectGroupController({
|
|
getStore: () => ({ getFolderWorkspaces: () => [workspace], removeFolderWorkspace }) as never,
|
|
resolveRepo: async () => {
|
|
throw new Error('unused')
|
|
},
|
|
notifyReposChanged,
|
|
resolveFolderConnectionId,
|
|
teardownFolderWorkspacePtys,
|
|
cleanupRemovedFolderWorkspaceState,
|
|
emitWorktreeLifecycle
|
|
})
|
|
return {
|
|
emitWorktreeLifecycle,
|
|
controller,
|
|
removeFolderWorkspace,
|
|
teardownFolderWorkspacePtys,
|
|
cleanupRemovedFolderWorkspaceState,
|
|
notifyReposChanged
|
|
}
|
|
}
|
|
|
|
describe('RuntimeProjectGroupController.deleteFolderWorkspace', () => {
|
|
it('tears down PTYs and runtime state before removing the catalog row', async () => {
|
|
const deps = createController(() => 'ssh-1')
|
|
|
|
await expect(deps.controller.deleteFolderWorkspace('ws-1')).resolves.toEqual({ deleted: true })
|
|
|
|
expect(deps.teardownFolderWorkspacePtys).toHaveBeenCalledWith('folder:ws-1', 'ssh-1')
|
|
expect(deps.cleanupRemovedFolderWorkspaceState).toHaveBeenCalledWith('folder:ws-1')
|
|
expect(deps.teardownFolderWorkspacePtys.mock.invocationCallOrder[0]).toBeLessThan(
|
|
deps.removeFolderWorkspace.mock.invocationCallOrder[0]!
|
|
)
|
|
expect(deps.notifyReposChanged).toHaveBeenCalledTimes(1)
|
|
expect(deps.emitWorktreeLifecycle).toHaveBeenCalledWith({
|
|
kind: 'removed',
|
|
worktreeId: 'folder:ws-1',
|
|
path: '/tmp/ws'
|
|
})
|
|
})
|
|
|
|
it('still deletes when the folder host is ambiguous, skipping only the PTY sweep', async () => {
|
|
const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
|
|
const deps = createController(() => {
|
|
throw new Error('folder_workspace_connection_ambiguous')
|
|
})
|
|
|
|
await expect(deps.controller.deleteFolderWorkspace('ws-1')).resolves.toEqual({ deleted: true })
|
|
|
|
expect(deps.teardownFolderWorkspacePtys).not.toHaveBeenCalled()
|
|
expect(deps.cleanupRemovedFolderWorkspaceState).toHaveBeenCalledWith('folder:ws-1')
|
|
expect(deps.removeFolderWorkspace).toHaveBeenCalledWith('ws-1')
|
|
expect(deps.emitWorktreeLifecycle).toHaveBeenCalledWith(
|
|
expect.objectContaining({ kind: 'removed', worktreeId: 'folder:ws-1' })
|
|
)
|
|
warn.mockRestore()
|
|
})
|
|
})
|