mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 09:07:40 +00:00
* feat(chat): Resume in New CLI for OpenCode and OMP chats OpenCode's and OMP's CLIs have no copy flag, but their chat protocol copies a conversation (ACP session/fork). For a fork of one of their chats, the chat's host now has a short-lived agent, launched exactly as the chat's own, copy the conversation; the terminal then opens the copy with a plain resume. The chat keeps its own conversation, so the CLI is never a second writer on it. The copy travels on the existing aiVault.prepareSessionResume fork request as an optional forkedSessionId; a host that predates it answers without one, and the client asks for an Orca update instead of resuming the original. * fix(chat): open an OpenCode 2.x chat's CLI copy with opencode, not opencode2 The copy kept the row's agent, so Resume in New CLI ran `opencode2 --standalone --session <copy>`, which OpenCode 2.x doesn't install. The chat's host now answers the copy with the agent whose CLI opens it: the chat's own. * fix(chat): type the copied conversation's agent as a history agent * fix: preserve independent chat copies through CLI launch * test: keep only the tests that pin user-visible behavior * fix(chat): validate OpenCode copies on their execution host * test(chat): expect copied OMP forks after main integration
46 lines
1.7 KiB
TypeScript
46 lines
1.7 KiB
TypeScript
import type { TuiAgent } from './tui-agent'
|
|
import { getAgentLaunchExecutableName } from './agent-command-line-intent'
|
|
import { findOptionOccurrence } from './command-option-occurrence'
|
|
|
|
export class OpenCodeCopyServerRouteError extends Error {
|
|
constructor() {
|
|
super(
|
|
'Remove --server from the OpenCode command or arguments in Settings to open a copy in a CLI.'
|
|
)
|
|
}
|
|
}
|
|
|
|
/** A configured server may not hold the copy saved by this execution host. */
|
|
export function assertOpenCodeCopyUsesLocalStore(args: readonly string[]): void {
|
|
if (findOptionOccurrence(args, ['--server'], true)) {
|
|
throw new OpenCodeCopyServerRouteError()
|
|
}
|
|
}
|
|
|
|
function openCodeCommandAgent(launchCommand: string | undefined): 'opencode' | 'opencode2' | null {
|
|
const binary = getAgentLaunchExecutableName(launchCommand)
|
|
return binary === 'opencode' || binary === 'opencode2' ? binary : null
|
|
}
|
|
|
|
export function isOpenCode2LaunchCommand(launchCommand: string | undefined): boolean {
|
|
return openCodeCommandAgent(launchCommand) === 'opencode2'
|
|
}
|
|
|
|
export function selectOpenCodeHookAgent(
|
|
launchAgent: TuiAgent | undefined,
|
|
launchCommand: string | undefined,
|
|
isEnabled: (agent: 'opencode' | 'opencode2') => boolean
|
|
): 'opencode' | 'opencode2' | null {
|
|
const explicit =
|
|
launchAgent === 'opencode' || launchAgent === 'opencode2'
|
|
? launchAgent
|
|
: launchAgent === undefined
|
|
? openCodeCommandAgent(launchCommand)
|
|
: null
|
|
// An explicit version selects its own integration; disabling it never substitutes the other.
|
|
if (explicit) {
|
|
return isEnabled(explicit) ? explicit : null
|
|
}
|
|
return isEnabled('opencode') ? 'opencode' : isEnabled('opencode2') ? 'opencode2' : null
|
|
}
|