mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 00:02:29 +00:00
* fix(resource-manager): resolve folder workspace names and groups * fix: recover local folder PTY attribution after restart * fix(resource-manager): keep ambiguous-id rows and open folder rows Ambiguity filtering removed both rows of a workspace-id collision from worktreeById, so step 3 of the merge dropped browser-only rows for any id present on two execution hosts. Carry ambiguity as a separate MergeContext signal that gates only folder host/name attribution; the existence check and the old repo-level host default are unchanged. Folder-workspace rows rendered as enabled buttons but navigateToWorktree resolved only worktrees, so clicks were a silent no-op. Route folder keys through activateAndRevealWorkspace, which owns host selection and path-status gating. * test(resource-manager): repair the merge-call ratchet anchor The ambiguous-id fix added `ambiguousWorktreeIds` after `worktreeById` in the mergeSnapshotAndSessions call, so the parity test's end anchor no longer matched: indexOf returned -1 and slice(start, -1) silently widened the scan to the rest of the file. The test still passed but stopped pinning the merge call site. Verified: removing `...resourceSessionBindings` now fails the test again. --------- Co-authored-by: m4air <m4air@Mac.localdomain> Co-authored-by: Neil <neil@stably.ai>
148 lines
5.7 KiB
TypeScript
148 lines
5.7 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 { 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,
|
|
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()
|
|
if (!group) {
|
|
throw new Error('Could not create project group')
|
|
}
|
|
const workspace = await state.createFolderWorkspace({
|
|
projectGroupId: group.id,
|
|
...folder
|
|
})
|
|
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
|
|
})
|
|
}
|
|
await window.__store!.getState().fetchMemorySnapshot()
|
|
},
|
|
{ theme, folders }
|
|
)
|
|
|
|
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()
|
|
if (!group) {
|
|
throw new Error('Could not create project group')
|
|
}
|
|
const folder = await state.createFolderWorkspace({
|
|
projectGroupId: group.id,
|
|
name: 'Recovered notes',
|
|
folderPath
|
|
})
|
|
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 page.evaluate(() => window.__store!.getState().fetchMemorySnapshot())
|
|
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 })
|
|
}
|
|
})
|