mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 01:27:35 +00:00
* feat(chat): Resume in New Native Chat for OpenCode terminal conversations An OpenCode conversation started in the terminal now offers "Resume in New Native Chat" in its Session History row menu and its tab's right-click menu, as Claude, Codex, Grok and OMP do: a new OpenCode chat takes it over, showing its history and continuing it. OpenCode 2.x rows (`opencode2`) and 1.x rows both open an OpenCode chat. Two pieces kept OpenCode off the shared adoption path. Its account is a locator, not a folder, so the transcript import now works over the account the chat pins, whatever its kind; the folder agents wrap their lookups in directoryTranscriptImport, unchanged. Its conversations live in a database, so the journal import reads the found database with the reader the OpenCode transcript view already uses. OpenCode refuses to reopen a session from another folder, so the workspace rule covers it too. * test(chat): Pi is now the agent with no transcript import * fix(chat): find an OpenCode 2.x terminal tab's Session History row The pane reports `opencode` while Session History lists the conversation as `opencode2`, so the pane header's and tab menu's Resume in New Native Chat found no row. Match by the chat agent that takes the conversation over. * Fix OpenCode chat adoption environment and pane eligibility * test(chat): adapt parent adoption fixtures to account identities * test: keep only the tests that pin user-visible behavior * refactor(chat): map a Session History row to its chat agent where the chat starts Both Resume in New Native Chat callers repeated the row-to-chat agent lookup. The launch now takes the row agent and maps it once, so the Session History actions file stays unchanged.
127 lines
4.5 KiB
TypeScript
127 lines
4.5 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import type { ManagedDataAccountsState } from '../../shared/managed-account-types'
|
|
import { restoreManagedDataAccountEnvironment } from '../../shared/managed-data-account-environment'
|
|
import {
|
|
environmentForStructuredOpenCodeAccountHome,
|
|
resolveStructuredOpenCodeAccountHome
|
|
} from './opencode-structured-account-home'
|
|
|
|
const first = '123e4567-e89b-42d3-a456-426614174000'
|
|
const second = '123e4567-e89b-42d3-a456-426614174001'
|
|
|
|
function managedAccounts() {
|
|
let activeAccountId: string | null = first
|
|
let available = new Set([first, second])
|
|
return {
|
|
list: (): ManagedDataAccountsState => ({
|
|
accounts: [...available].map((id) => ({ id, label: id, integrations: [], createdAt: 0 })),
|
|
activeAccountId
|
|
}),
|
|
restoreOriginalEnvironment: (environment: Record<string, string | undefined>) =>
|
|
restoreManagedDataAccountEnvironment(environment),
|
|
environmentForAccount: (_provider: 'opencode' | 'devin', id: string) => {
|
|
if (!available.has(id)) {
|
|
throw new Error('Managed account not found.')
|
|
}
|
|
return {
|
|
XDG_DATA_HOME: `/profiles/${id}/data`,
|
|
XDG_STATE_HOME: `/profiles/${id}/state`,
|
|
OPENCODE_DB: 'opencode.db',
|
|
OPENCODE_AUTH_CONTENT: ''
|
|
}
|
|
},
|
|
select: (id: string | null) => {
|
|
activeAccountId = id
|
|
},
|
|
remove: (id: string) => {
|
|
available = new Set([...available].filter((entry) => entry !== id))
|
|
}
|
|
}
|
|
}
|
|
|
|
describe('structured OpenCode account binding', () => {
|
|
it('records only that the chat has no managed profile', () => {
|
|
const accounts = managedAccounts()
|
|
accounts.select(null)
|
|
expect(resolveStructuredOpenCodeAccountHome({ managedAccounts: accounts })).toEqual({
|
|
kind: 'opencode',
|
|
locator: { kind: 'unmanaged' }
|
|
})
|
|
})
|
|
|
|
it('uses the pinned managed profile after selection changes and refuses removal', () => {
|
|
const accounts = managedAccounts()
|
|
const binding = resolveStructuredOpenCodeAccountHome({ managedAccounts: accounts })
|
|
accounts.select(second)
|
|
const environment = environmentForStructuredOpenCodeAccountHome(binding, {
|
|
managedAccounts: accounts,
|
|
baseEnvironment: { PATH: '/bin', XDG_DATA_HOME: '/settings/data', OPENCODE_DB: 'work.db' }
|
|
})
|
|
expect(environment.XDG_DATA_HOME).toBe(`/profiles/${first}/data`)
|
|
expect(environment.OPENCODE_DB).toBe('opencode.db')
|
|
expect(resolveStructuredOpenCodeAccountHome({ managedAccounts: accounts }).locator).toEqual({
|
|
kind: 'managed',
|
|
managedProfileId: second
|
|
})
|
|
accounts.remove(first)
|
|
expect(() =>
|
|
environmentForStructuredOpenCodeAccountHome(binding, {
|
|
managedAccounts: accounts,
|
|
baseEnvironment: {}
|
|
})
|
|
).toThrow('Managed account not found.')
|
|
})
|
|
|
|
it("passes the user's inline credentials, relative paths and database through unchanged", () => {
|
|
const accounts = managedAccounts()
|
|
accounts.select(null)
|
|
const baseEnvironment = {
|
|
PATH: '/bin',
|
|
HOME: 'relative/home',
|
|
XDG_DATA_HOME: 'relative/data',
|
|
XDG_STATE_HOME: 'relative/state',
|
|
OPENCODE_DB: 'custom.db',
|
|
OPENCODE_AUTH_CONTENT: '{"provider":{"type":"api","key":"inline"}}'
|
|
}
|
|
const binding = resolveStructuredOpenCodeAccountHome({ managedAccounts: accounts })
|
|
expect(
|
|
environmentForStructuredOpenCodeAccountHome(binding, {
|
|
managedAccounts: accounts,
|
|
baseEnvironment
|
|
})
|
|
).toEqual(baseEnvironment)
|
|
})
|
|
|
|
it("undoes Orca's inherited managed overlay before passing the environment through", () => {
|
|
const accounts = managedAccounts()
|
|
accounts.select(null)
|
|
const environment = environmentForStructuredOpenCodeAccountHome(
|
|
{ kind: 'opencode', locator: { kind: 'unmanaged' } },
|
|
{
|
|
managedAccounts: accounts,
|
|
baseEnvironment: {
|
|
ORCA_DATA_ACCOUNT_PROVIDER: 'opencode',
|
|
ORCA_DATA_ACCOUNT_DATA_HOME: '/old/data',
|
|
ORCA_DATA_ACCOUNT_STATE_HOME: '/old/state',
|
|
ORCA_DATA_ACCOUNT_ORIGINAL_ENV: JSON.stringify({
|
|
XDG_DATA_HOME: '/original/data',
|
|
XDG_STATE_HOME: null,
|
|
OPENCODE_DB: 'original.db',
|
|
OPENCODE_AUTH_CONTENT: null
|
|
}),
|
|
XDG_DATA_HOME: '/old/data',
|
|
XDG_STATE_HOME: '/old/state',
|
|
OPENCODE_DB: 'opencode.db',
|
|
OPENCODE_AUTH_CONTENT: '',
|
|
PATH: '/bin'
|
|
}
|
|
}
|
|
)
|
|
expect(environment).toEqual({
|
|
XDG_DATA_HOME: '/original/data',
|
|
OPENCODE_DB: 'original.db',
|
|
PATH: '/bin'
|
|
})
|
|
})
|
|
})
|