mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 08:03:39 +00:00
Show OMP sessions in AI Vault history
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { buildAiVaultResumeCommand } from '../../shared/ai-vault-types'
|
||||
|
||||
describe('buildAiVaultResumeCommand', () => {
|
||||
it('wraps Windows cwd changes in cmd so PowerShell and cmd launch the same resume command', () => {
|
||||
expect(
|
||||
buildAiVaultResumeCommand({
|
||||
agent: 'codex',
|
||||
sessionId: 'session-1',
|
||||
cwd: 'C:\\Users\\Ada Lovelace\\repo',
|
||||
platform: 'win32'
|
||||
})
|
||||
).toBe('cmd /d /s /c "cd /d ""C:\\Users\\Ada Lovelace\\repo"" && codex resume ""session-1"""')
|
||||
|
||||
expect(
|
||||
buildAiVaultResumeCommand({
|
||||
agent: 'omp',
|
||||
sessionId: 'omp session',
|
||||
cwd: 'C:\\Users\\Ada Lovelace\\repo',
|
||||
platform: 'win32'
|
||||
})
|
||||
).toBe('cmd /d /s /c "cd /d ""C:\\Users\\Ada Lovelace\\repo"" && omp --resume ""omp session"""')
|
||||
})
|
||||
|
||||
it('carries non-default Codex homes in copied resume commands', () => {
|
||||
expect(
|
||||
buildAiVaultResumeCommand({
|
||||
agent: 'codex',
|
||||
sessionId: 'session-1',
|
||||
cwd: '/repo/app',
|
||||
platform: 'darwin',
|
||||
codexHome: '/Users/ada/Library/Application Support/Orca/codex-runtime-home/home'
|
||||
})
|
||||
).toBe(
|
||||
"cd '/repo/app' && CODEX_HOME='/Users/ada/Library/Application Support/Orca/codex-runtime-home/home' codex resume 'session-1'"
|
||||
)
|
||||
|
||||
expect(
|
||||
buildAiVaultResumeCommand({
|
||||
agent: 'codex',
|
||||
sessionId: 'session-1',
|
||||
cwd: 'C:\\Users\\Ada Lovelace\\repo',
|
||||
platform: 'win32',
|
||||
codexHome: 'C:\\Users\\Ada\\AppData\\Roaming\\Orca\\codex-runtime-home\\home'
|
||||
})
|
||||
).toBe(
|
||||
'cmd /d /s /c "cd /d ""C:\\Users\\Ada Lovelace\\repo"" && set ""CODEX_HOME=C:\\Users\\Ada\\AppData\\Roaming\\Orca\\codex-runtime-home\\home"" && codex resume ""session-1"""'
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -67,6 +67,8 @@ export async function parseAgentSessionFile(
|
||||
return parseMessageGraphSessionFile('openclaw', candidate.file, platform)
|
||||
case 'pi':
|
||||
return parseMessageGraphSessionFile('pi', candidate.file, platform)
|
||||
case 'omp':
|
||||
return parseMessageGraphSessionFile('omp', candidate.file, platform)
|
||||
case 'droid':
|
||||
return parseDroidSessionFile(candidate.file, platform)
|
||||
case 'devin':
|
||||
|
||||
@@ -117,6 +117,7 @@ describe('scanAiVaultSessions Codex worker sessions', () => {
|
||||
openclawStateDir: join(root, 'openclaw-state'),
|
||||
openclawLegacyStateDir: join(root, 'openclaw-legacy-state'),
|
||||
piSessionsDir: join(root, 'pi-sessions'),
|
||||
ompSessionsDir: join(root, 'omp-sessions'),
|
||||
droidSessionsDir: join(root, 'droid-sessions'),
|
||||
droidProjectsDir: join(root, 'droid-projects'),
|
||||
kimiSessionsDir: join(root, 'kimi-sessions'),
|
||||
|
||||
@@ -155,7 +155,7 @@ export function rovoPartsText(parts: unknown[], role: 'user' | 'assistant'): str
|
||||
}
|
||||
|
||||
export async function parseMessageGraphSessionFile(
|
||||
agent: 'openclaw' | 'pi',
|
||||
agent: 'openclaw' | 'pi' | 'omp',
|
||||
file: FileWithMtime,
|
||||
platform: NodeJS.Platform = process.platform
|
||||
): Promise<AiVaultSession | null> {
|
||||
@@ -181,10 +181,12 @@ export async function parseMessageGraphSessionFile(
|
||||
accumulator.sessionId = sessionId
|
||||
}
|
||||
accumulator.cwd = extractString(record.cwd) ?? accumulator.cwd
|
||||
accumulator.title ??= normalizeTitleText(extractString(record.title) ?? '')
|
||||
continue
|
||||
}
|
||||
if (record.type === 'model_change') {
|
||||
accumulator.model = extractString(record.modelId) ?? accumulator.model
|
||||
accumulator.model =
|
||||
extractString(record.model) ?? extractString(record.modelId) ?? accumulator.model
|
||||
continue
|
||||
}
|
||||
if (record.type !== 'message') {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { mkdtemp, mkdir, rm, writeFile } from 'fs/promises'
|
||||
import { tmpdir } from 'os'
|
||||
import { join } from 'path'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { scanAiVaultSessions } from './session-scanner'
|
||||
|
||||
let tempRoots: string[] = []
|
||||
|
||||
afterEach(async () => {
|
||||
vi.restoreAllMocks()
|
||||
await Promise.all(tempRoots.map((root) => rm(root, { recursive: true, force: true })))
|
||||
tempRoots = []
|
||||
})
|
||||
|
||||
function isolatedGrokScanRoots(root: string) {
|
||||
return {
|
||||
claudeProjectsDir: join(root, 'claude-projects'),
|
||||
codexSessionsDir: join(root, 'codex-sessions'),
|
||||
geminiSessionsDir: join(root, 'gemini-sessions'),
|
||||
copilotSessionsDir: join(root, 'copilot-sessions'),
|
||||
cursorProjectsDir: join(root, 'cursor-projects'),
|
||||
opencodeStorageDir: join(root, 'opencode-storage'),
|
||||
opencodeDbPaths: [] as readonly string[],
|
||||
grokSessionsDir: join(root, 'grok-sessions'),
|
||||
devinTranscriptsDir: join(root, 'devin-transcripts'),
|
||||
hermesSessionsDir: join(root, 'hermes-sessions'),
|
||||
rovoSessionsDir: join(root, 'rovo-sessions'),
|
||||
openclawStateDir: join(root, 'openclaw-state'),
|
||||
openclawLegacyStateDir: join(root, 'openclaw-legacy-state'),
|
||||
piSessionsDir: join(root, 'pi-sessions'),
|
||||
ompSessionsDir: join(root, 'omp-sessions'),
|
||||
droidSessionsDir: join(root, 'droid-sessions'),
|
||||
droidProjectsDir: join(root, 'droid-projects'),
|
||||
kimiSessionsDir: join(root, 'kimi-sessions')
|
||||
}
|
||||
}
|
||||
|
||||
function jsonLines(records: unknown[]): string {
|
||||
return records.map((record) => JSON.stringify(record)).join('\n')
|
||||
}
|
||||
|
||||
describe('scanAiVaultSessions Grok envelopes', () => {
|
||||
it('strips newline-heavy Grok user_query envelopes without regex matching', async () => {
|
||||
const matchSpy = vi.spyOn(String.prototype, 'match')
|
||||
const root = await mkdtemp(join(tmpdir(), 'orca-ai-vault-grok-large-'))
|
||||
tempRoots.push(root)
|
||||
const roots = isolatedGrokScanRoots(root)
|
||||
const sessionDir = join(roots.grokSessionsDir, encodeURIComponent('/tmp/grok'), 'large-session')
|
||||
const requestText = 'Grok large title\n'.repeat(300)
|
||||
await mkdir(sessionDir, { recursive: true })
|
||||
await writeFile(
|
||||
join(sessionDir, 'summary.json'),
|
||||
JSON.stringify({
|
||||
info: { id: 'large-session', cwd: '/tmp/grok' },
|
||||
created_at: '2026-05-01T10:04:00.000Z'
|
||||
})
|
||||
)
|
||||
await writeFile(
|
||||
join(sessionDir, 'chat_history.jsonl'),
|
||||
jsonLines([
|
||||
{
|
||||
type: 'user',
|
||||
content: `<USER_INFO>context</USER_INFO><USER_QUERY>\n${requestText}</USER_QUERY>`
|
||||
}
|
||||
])
|
||||
)
|
||||
|
||||
const result = await scanAiVaultSessions({
|
||||
...roots,
|
||||
platform: 'darwin',
|
||||
limit: 5
|
||||
})
|
||||
|
||||
expect(result.issues).toEqual([])
|
||||
expect(result.sessions[0]?.title).toContain('Grok large title')
|
||||
expect(result.sessions[0]?.title).not.toContain('USER_QUERY')
|
||||
const usedGrokWrapperMatch = matchSpy.mock.calls.some(
|
||||
([pattern]) =>
|
||||
pattern instanceof RegExp &&
|
||||
pattern.source.includes('<user_query>') &&
|
||||
pattern.source.includes('[\\s\\S]')
|
||||
)
|
||||
expect(usedGrokWrapperMatch).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -34,6 +34,7 @@ function isolatedScanRoots(root: string) {
|
||||
openclawStateDir: join(root, 'openclaw-state'),
|
||||
openclawLegacyStateDir: join(root, 'openclaw-legacy-state'),
|
||||
piSessionsDir: join(root, 'pi-sessions'),
|
||||
ompSessionsDir: join(root, 'omp-sessions'),
|
||||
droidSessionsDir: join(root, 'droid-sessions'),
|
||||
droidProjectsDir: join(root, 'droid-projects'),
|
||||
kimiSessionsDir: join(root, 'kimi-sessions')
|
||||
|
||||
@@ -28,6 +28,7 @@ const OPENCLAW_STATE_DIR = process.env.OPENCLAW_STATE_DIR?.trim() || join(homedi
|
||||
const PI_SESSIONS_DIR = normalizePiSessionsDir(
|
||||
process.env.PI_CODING_AGENT_DIR?.trim() || join(homedir(), '.pi', 'agent', 'sessions')
|
||||
)
|
||||
const OMP_SESSIONS_DIR = normalizePiSessionsDir(join(homedir(), '.omp', 'agent', 'sessions'))
|
||||
// Why: Devin ATIF transcripts are stored under <DEVIN_HOME>/transcripts.
|
||||
const DEVIN_TRANSCRIPTS_DIR = join(
|
||||
process.env.DEVIN_HOME?.trim() || join(homedir(), '.local', 'share', 'devin', 'cli'),
|
||||
@@ -114,7 +115,8 @@ function standardDiscoveries(
|
||||
...devinDiscoveries(options, wslHomeDirs, limit, issues),
|
||||
...hermesDiscoveries(options, wslHomeDirs, limit, issues),
|
||||
...rovoDiscoveries(options, wslHomeDirs, limit, issues),
|
||||
...piDiscoveries(options, wslHomeDirs, limit, issues)
|
||||
...piDiscoveries(options, wslHomeDirs, limit, issues),
|
||||
...ompDiscoveries(options, wslHomeDirs, limit, issues)
|
||||
]
|
||||
}
|
||||
|
||||
@@ -234,6 +236,21 @@ function piDiscoveries(
|
||||
)
|
||||
}
|
||||
|
||||
function ompDiscoveries(
|
||||
options: AiVaultScanOptions,
|
||||
wslHomeDirs: readonly string[],
|
||||
limit: number,
|
||||
issues: AiVaultScanIssue[]
|
||||
): Promise<SessionFileDiscovery>[] {
|
||||
return sessionRootDirs(options.ompSessionsDir ?? OMP_SESSIONS_DIR, wslHomeDirs, [
|
||||
'.omp',
|
||||
'agent',
|
||||
'sessions'
|
||||
]).map((rootDir) =>
|
||||
discoverFiles({ rootDir, limit, agent: 'omp', issues, extensions: ['.jsonl'] })
|
||||
)
|
||||
}
|
||||
|
||||
function openClawDiscovery(
|
||||
options: AiVaultScanOptions,
|
||||
wslHomeDirs: readonly string[],
|
||||
|
||||
@@ -24,6 +24,7 @@ export type AiVaultScanOptions = {
|
||||
openclawStateDir?: string
|
||||
openclawLegacyStateDir?: string
|
||||
piSessionsDir?: string
|
||||
ompSessionsDir?: string
|
||||
droidSessionsDir?: string
|
||||
droidProjectsDir?: string
|
||||
kimiSessionsDir?: string
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { mkdtemp, mkdir, rm, writeFile } from 'fs/promises'
|
||||
import { tmpdir } from 'os'
|
||||
import { join } from 'path'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { AI_VAULT_AGENTS, buildAiVaultResumeCommand } from '../../shared/ai-vault-types'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import { AI_VAULT_AGENTS } from '../../shared/ai-vault-types'
|
||||
import { scanAiVaultSessions } from './session-scanner'
|
||||
|
||||
let tempRoots: string[] = []
|
||||
|
||||
afterEach(async () => {
|
||||
vi.restoreAllMocks()
|
||||
await Promise.all(tempRoots.map((root) => rm(root, { recursive: true, force: true })))
|
||||
tempRoots = []
|
||||
})
|
||||
@@ -31,6 +30,7 @@ function isolatedScanRoots(root: string) {
|
||||
openclawStateDir: join(root, 'openclaw-state'),
|
||||
openclawLegacyStateDir: join(root, 'openclaw-legacy-state'),
|
||||
piSessionsDir: join(root, 'pi-sessions'),
|
||||
ompSessionsDir: join(root, 'omp-sessions'),
|
||||
droidSessionsDir: join(root, 'droid-sessions'),
|
||||
droidProjectsDir: join(root, 'droid-projects'),
|
||||
kimiSessionsDir: join(root, 'kimi-sessions')
|
||||
@@ -611,6 +611,42 @@ describe('scanAiVaultSessions', () => {
|
||||
])
|
||||
)
|
||||
|
||||
await mkdir(join(roots.ompSessionsDir, encodeURIComponent('/tmp/omp')), { recursive: true })
|
||||
await writeFile(
|
||||
join(roots.ompSessionsDir, encodeURIComponent('/tmp/omp'), '2026-05-01_omp-session.jsonl'),
|
||||
jsonLines([
|
||||
{
|
||||
type: 'session',
|
||||
id: 'omp-session',
|
||||
title: 'OMP header title',
|
||||
timestamp: '2026-05-01T10:08:30.000Z',
|
||||
cwd: '/tmp/omp'
|
||||
},
|
||||
{
|
||||
type: 'model_change',
|
||||
timestamp: '2026-05-01T10:08:31.000Z',
|
||||
model: 'omp-model'
|
||||
},
|
||||
{
|
||||
type: 'message',
|
||||
timestamp: '2026-05-01T10:08:32.000Z',
|
||||
message: {
|
||||
role: 'user',
|
||||
content: [{ type: 'text', text: 'OMP first user fallback title' }]
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'message',
|
||||
timestamp: '2026-05-01T10:08:33.000Z',
|
||||
message: {
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text: 'Done' }],
|
||||
usage: { input: 3, output: 5, cacheRead: 7, cacheWrite: 11 }
|
||||
}
|
||||
}
|
||||
])
|
||||
)
|
||||
|
||||
await mkdir(roots.devinTranscriptsDir, { recursive: true })
|
||||
await writeFile(
|
||||
join(roots.devinTranscriptsDir, 'devin-session.json'),
|
||||
@@ -746,92 +782,21 @@ describe('scanAiVaultSessions', () => {
|
||||
"cd '/tmp/openclaw' && openclaw --resume 'openclaw-session'"
|
||||
)
|
||||
expect(commandByAgent.get('pi')).toBe("cd '/tmp/pi' && pi --session 'pi-session'")
|
||||
expect(commandByAgent.get('omp')).toBe("cd '/tmp/omp' && omp --resume 'omp-session'")
|
||||
expect(commandByAgent.get('devin')).toBe("cd '/tmp/devin' && devin --resume 'devin-session'")
|
||||
expect(commandByAgent.get('droid')).toBe("cd '/tmp/droid' && droid --resume 'droid-session'")
|
||||
expect(commandByAgent.get('kimi')).toBe(
|
||||
"cd '/tmp/kimi' && kimi --session 'session_kimi-session'"
|
||||
)
|
||||
})
|
||||
|
||||
it('strips newline-heavy Grok user_query envelopes without regex matching', async () => {
|
||||
const matchSpy = vi.spyOn(String.prototype, 'match')
|
||||
const root = await mkdtemp(join(tmpdir(), 'orca-ai-vault-grok-large-'))
|
||||
tempRoots.push(root)
|
||||
const roots = isolatedScanRoots(root)
|
||||
const sessionDir = join(roots.grokSessionsDir, encodeURIComponent('/tmp/grok'), 'large-session')
|
||||
const requestText = 'Grok large title\n'.repeat(300)
|
||||
await mkdir(sessionDir, { recursive: true })
|
||||
await writeFile(
|
||||
join(sessionDir, 'summary.json'),
|
||||
JSON.stringify({
|
||||
info: { id: 'large-session', cwd: '/tmp/grok' },
|
||||
created_at: '2026-05-01T10:04:00.000Z'
|
||||
})
|
||||
)
|
||||
await writeFile(
|
||||
join(sessionDir, 'chat_history.jsonl'),
|
||||
jsonLines([
|
||||
{
|
||||
type: 'user',
|
||||
content: `<USER_INFO>context</USER_INFO><USER_QUERY>\n${requestText}</USER_QUERY>`
|
||||
}
|
||||
])
|
||||
)
|
||||
|
||||
const result = await scanAiVaultSessions({
|
||||
...roots,
|
||||
platform: 'darwin',
|
||||
limit: 5
|
||||
const omp = result.sessions.find((session) => session.agent === 'omp')
|
||||
expect(omp).toMatchObject({
|
||||
sessionId: 'omp-session',
|
||||
title: 'OMP header title',
|
||||
cwd: '/tmp/omp',
|
||||
model: 'omp-model',
|
||||
messageCount: 2,
|
||||
totalTokens: 26
|
||||
})
|
||||
|
||||
expect(result.issues).toEqual([])
|
||||
expect(result.sessions[0]?.title).toContain('Grok large title')
|
||||
expect(result.sessions[0]?.title).not.toContain('USER_QUERY')
|
||||
const usedGrokWrapperMatch = matchSpy.mock.calls.some(
|
||||
([pattern]) =>
|
||||
pattern instanceof RegExp &&
|
||||
pattern.source.includes('<user_query>') &&
|
||||
pattern.source.includes('[\\s\\S]')
|
||||
)
|
||||
expect(usedGrokWrapperMatch).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('buildAiVaultResumeCommand', () => {
|
||||
it('wraps Windows cwd changes in cmd so PowerShell and cmd launch the same resume command', () => {
|
||||
expect(
|
||||
buildAiVaultResumeCommand({
|
||||
agent: 'codex',
|
||||
sessionId: 'session-1',
|
||||
cwd: 'C:\\Users\\Ada Lovelace\\repo',
|
||||
platform: 'win32'
|
||||
})
|
||||
).toBe('cmd /d /s /c "cd /d ""C:\\Users\\Ada Lovelace\\repo"" && codex resume ""session-1"""')
|
||||
})
|
||||
|
||||
it('carries non-default Codex homes in copied resume commands', () => {
|
||||
expect(
|
||||
buildAiVaultResumeCommand({
|
||||
agent: 'codex',
|
||||
sessionId: 'session-1',
|
||||
cwd: '/repo/app',
|
||||
platform: 'darwin',
|
||||
codexHome: '/Users/ada/Library/Application Support/Orca/codex-runtime-home/home'
|
||||
})
|
||||
).toBe(
|
||||
"cd '/repo/app' && CODEX_HOME='/Users/ada/Library/Application Support/Orca/codex-runtime-home/home' codex resume 'session-1'"
|
||||
)
|
||||
|
||||
expect(
|
||||
buildAiVaultResumeCommand({
|
||||
agent: 'codex',
|
||||
sessionId: 'session-1',
|
||||
cwd: 'C:\\Users\\Ada Lovelace\\repo',
|
||||
platform: 'win32',
|
||||
codexHome: 'C:\\Users\\Ada\\AppData\\Roaming\\Orca\\codex-runtime-home\\home'
|
||||
})
|
||||
).toBe(
|
||||
'cmd /d /s /c "cd /d ""C:\\Users\\Ada Lovelace\\repo"" && set ""CODEX_HOME=C:\\Users\\Ada\\AppData\\Roaming\\Orca\\codex-runtime-home\\home"" && codex resume ""session-1"""'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { AiVaultSession } from '../../../../shared/ai-vault-types'
|
||||
import { AI_VAULT_AGENTS, type AiVaultSession } from '../../../../shared/ai-vault-types'
|
||||
import { TUI_AGENT_CONFIG } from '../../../../shared/tui-agent-config'
|
||||
import {
|
||||
AI_VAULT_SESSION_FILTER_QUERY_MAX_BYTES,
|
||||
deriveAiVaultWorkspaceScopePaths,
|
||||
@@ -30,6 +31,11 @@ const baseSession: AiVaultSession = {
|
||||
}
|
||||
|
||||
describe('filterAiVaultSessions', () => {
|
||||
it('offers OMP in the agent filter because OMP is a supported TUI agent', () => {
|
||||
expect(TUI_AGENT_CONFIG.omp).toBeDefined()
|
||||
expect(AI_VAULT_AGENTS).toContain('omp')
|
||||
})
|
||||
|
||||
it('filters by workspace, agent, plain terms, repo: and path: operators', () => {
|
||||
const sessions: AiVaultSession[] = [
|
||||
baseSession,
|
||||
|
||||
@@ -9,6 +9,23 @@ vi.mock('@/lib/new-workspace', () => ({
|
||||
CLIENT_PLATFORM: 'win32'
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/local-preflight-context', () => ({
|
||||
getLocalProjectExecutionRuntimeContext: (
|
||||
state: Pick<AppState, 'projects'>,
|
||||
_worktreeId: string | null | undefined,
|
||||
platform: NodeJS.Platform
|
||||
) => {
|
||||
if (platform !== 'win32') {
|
||||
return undefined
|
||||
}
|
||||
const preference = state.projects[0]?.localWindowsRuntimePreference
|
||||
if (preference?.kind !== 'wsl') {
|
||||
return undefined
|
||||
}
|
||||
return { status: 'resolved', runtime: preference }
|
||||
}
|
||||
}))
|
||||
|
||||
type RuntimePreference = { kind: 'windows-host' } | { kind: 'wsl'; distro: string }
|
||||
|
||||
function makeState(args: {
|
||||
@@ -63,6 +80,19 @@ describe('ai vault resume command runtime', () => {
|
||||
}
|
||||
})
|
||||
).toBe('cmd /d /s /c "cd /d ""C:\\Users\\alice\\repo"" && claude --resume ""session one"""')
|
||||
|
||||
expect(
|
||||
buildAiVaultResumeCommandForWorktree({
|
||||
state,
|
||||
worktreeId: 'repo-1::worktree-1',
|
||||
session: {
|
||||
agent: 'omp',
|
||||
sessionId: 'omp session',
|
||||
cwd: 'C:\\Users\\alice\\repo',
|
||||
codexHome: null
|
||||
}
|
||||
})
|
||||
).toBe('cmd /d /s /c "cd /d ""C:\\Users\\alice\\repo"" && omp --resume ""omp session"""')
|
||||
})
|
||||
|
||||
it('uses POSIX command wrapping for Windows-path projects forced to WSL', () => {
|
||||
|
||||
@@ -6,6 +6,7 @@ export const AI_VAULT_AGENTS = [
|
||||
'codex',
|
||||
'hermes',
|
||||
'pi',
|
||||
'omp',
|
||||
'cursor',
|
||||
'gemini',
|
||||
'rovo',
|
||||
@@ -28,6 +29,7 @@ export const AI_VAULT_AGENT_LABELS = {
|
||||
codex: 'Codex',
|
||||
hermes: 'Hermes',
|
||||
pi: 'Pi',
|
||||
omp: 'OMP',
|
||||
cursor: 'Cursor',
|
||||
gemini: 'Gemini',
|
||||
rovo: 'Rovo Dev',
|
||||
@@ -147,6 +149,9 @@ function buildAgentResumeInvocation(
|
||||
return `${baseCommand} --session ${sessionArg}`
|
||||
case 'copilot':
|
||||
return `${baseCommand} --resume=${sessionArg}`
|
||||
// Why: OMP stores Pi-shaped transcripts, but its CLI resumes with
|
||||
// `omp --resume <id>` rather than Pi's `--session` flag.
|
||||
case 'omp':
|
||||
case 'claude':
|
||||
case 'cursor':
|
||||
case 'gemini':
|
||||
|
||||
Reference in New Issue
Block a user