Files
orca/tests/e2e/resource-manager-folder-labels.spec.ts
T
Jinjing 8fc1698ebb Add Resource Manager PTY inventory and checked terminal termination (#31593)
* feat(resources): end local terminals with checked identity checks

- Add a PTYs view to the Resource Manager that lists local terminals and can end one. Before stopping, the host confirms the terminal's incarnation, agent ownership, and attachments. This prevents ending a same-ID replacement that started after the list was read.
- Bump the daemon protocol to v50 and gate the new fenced kill on it. Older daemons ignore the extra fields, so the client refuses End instead of sending an unchecked kill.
- Admit diagnostic reads (PTY listing and memory snapshot) only while the Resources view is visible, so a hidden window does no background scanning.
- Report incarnation and host on spawn and exit events so the renderer can match them to the terminal it showed.
- Replace the popover's terminal-session list with the new inventory and move memory polling into the Resources view.

* Show unrouted daemon PTYs in the Resource Manager

* Simplify PTY controls and clarify safe termination

* Format local build compatibility protocol lists

* Add PTY resource management localization strings

* Harden PTY resource manager test fixtures

* Use typed IPC event in PTY kill test fixture

* Refine local PTY resource view model typing

* Refine local PTY resource view model typing

* Include local host identity in PTY lifecycle event tests
2026-10-22 12:20:01 -07:00

156 lines
6.0 KiB
TypeScript

import { mkdtempSync, mkdirSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { expect, test } from './helpers/orca-app'
import { makeResourceManagerFixtureVisible } from './helpers/resource-manager-visible-fixture'
import { waitForSessionReady } from './helpers/store'
import { createRestartSession } from './helpers/orca-restart'
test.use({ seedTestRepo: false })
for (const theme of ['dark', 'light'] as const) {
test(`Resource Manager names folder workspaces and their groups (${theme})`, async ({
orcaPage,
electronApp,
registerPostElectronShutdownCleanup
}, testInfo) => {
const root = mkdtempSync(join(tmpdir(), 'orca-resource-folders-'))
registerPostElectronShutdownCleanup(async () => rmSync(root, { recursive: true, force: true }))
const folders = ['Release notes', 'Customer research'].map((name) => {
const folderPath = join(root, name)
mkdirSync(folderPath)
return { name, folderPath }
})
await waitForSessionReady(orcaPage)
await orcaPage.setViewportSize({ width: 1200, height: 900 })
await orcaPage.evaluate(
async ({ theme, folders }) => {
const state = window.__store!.getState()
await state.updateSettingsOrThrow({ theme })
for (const [index, folder] of folders.entries()) {
const group = await window.api.projectGroups.create({
name: index === 0 ? 'Documentation' : 'Product',
parentPath: folder.folderPath,
createdFrom: 'folder-scan'
})
await state.fetchProjectGroups({ runtimeEnvironmentId: null, throwOnError: true })
if (!group) {
throw new Error('Could not create project group')
}
const workspace = await state.createFolderWorkspace(
{
projectGroupId: group.id,
...folder
},
{ runtimeEnvironmentId: null }
)
if (!workspace) {
throw new Error('Could not create folder workspace')
}
await window.api.pty.spawn({
cols: 80,
rows: 24,
cwd: workspace.folderPath,
worktreeId: `folder:${workspace.id}`,
initiallyHidden: true
})
}
},
{ theme, folders }
)
await makeResourceManagerFixtureVisible(electronApp, orcaPage)
await orcaPage.getByRole('button', { name: /^Resource Manager,/ }).click()
const popover = orcaPage.getByRole('dialog')
await expect(popover.getByText('Resource Manager', { exact: true })).toBeVisible()
await expect(popover.getByRole('button', { name: /^Resume workspace/ })).toHaveCount(2)
const screenshot = testInfo.outputPath(`resource-manager-folders-${theme}.png`)
await orcaPage.screenshot({ path: screenshot, animations: 'disabled' })
await testInfo.attach(`resource-manager-folders-${theme}`, {
path: screenshot,
contentType: 'image/png'
})
await expect(popover.getByText('Documentation', { exact: true })).toBeVisible()
await expect(popover.getByText('Product', { exact: true })).toBeVisible()
for (const { name } of folders) {
await expect(
popover.getByRole('button', { name: `Resume workspace ${name}`, exact: true })
).toBeVisible()
}
await expect(popover).not.toContainText('folder:')
})
}
test('names a folder terminal recovered from the daemon after restart without an open tab', async (// oxlint-disable-next-line no-empty-pattern -- Playwright requires destructuring to request no fixtures.
{}, testInfo) => {
const root = mkdtempSync(join(tmpdir(), 'orca-recovered-folder-'))
const session = createRestartSession(testInfo)
let launched: Awaited<ReturnType<typeof session.launch>> | undefined
try {
launched = await session.launch()
await waitForSessionReady(launched.page)
await launched.page.evaluate(async (folderPath) => {
const state = window.__store!.getState()
await state.updateSettingsOrThrow({ theme: 'dark' })
const group = await window.api.projectGroups.create({
name: 'Documentation',
parentPath: folderPath,
createdFrom: 'folder-scan'
})
await state.fetchProjectGroups({ runtimeEnvironmentId: null, throwOnError: true })
if (!group) {
throw new Error('Could not create project group')
}
const folder = await state.createFolderWorkspace(
{
projectGroupId: group.id,
name: 'Recovered notes',
folderPath
},
{ runtimeEnvironmentId: null }
)
if (!folder) {
throw new Error('Could not create folder workspace')
}
await window.api.pty.spawn({
cols: 80,
rows: 24,
cwd: folderPath,
worktreeId: `folder:${folder.id}`,
initiallyHidden: true
})
}, root)
await session.close(launched.app)
launched = await session.launch()
const page = launched.page
await waitForSessionReady(page)
await page.setViewportSize({ width: 1200, height: 900 })
await makeResourceManagerFixtureVisible(launched.app, page)
await page.getByRole('button', { name: /^Resource Manager,/ }).click()
const popover = page.getByRole('dialog')
await expect(popover.getByText('Resource Manager', { exact: true })).toBeVisible()
try {
await expect(
popover.getByRole('button', { name: 'Resume workspace Recovered notes', exact: true })
).toBeVisible()
await expect(popover.getByText(/^pid \d+$/)).toBeVisible()
await expect(popover).not.toContainText('Unattributed')
await expect(popover).not.toContainText('folder:')
} finally {
const screenshot = testInfo.outputPath('resource-manager-recovered-folder.png')
await page.screenshot({ path: screenshot, animations: 'disabled' })
await testInfo.attach('resource-manager-recovered-folder', {
path: screenshot,
contentType: 'image/png'
})
}
} finally {
if (launched) {
await session.close(launched.app)
}
await session.dispose()
rmSync(root, { recursive: true, force: true })
}
})