feat(coding-agent): enabled importing foreign sessions from claude and codex
- Implemented session stores and metadata converters to import Claude and Codex sessions into OMP. - Added `--from-claude` and `--from-codex` CLI flags and `/resume` command arguments for foreign session resolution. - Updated session selector components and controllers to support listing and picking external agent sessions. - Added comprehensive unit tests and documentation covering foreign session import functionality.
This commit is contained in:
@@ -44,6 +44,8 @@ export interface Args {
|
||||
advisor?: boolean;
|
||||
continue?: boolean;
|
||||
resume?: string | true;
|
||||
fromClaude?: boolean;
|
||||
fromCodex?: boolean;
|
||||
help?: boolean;
|
||||
version?: boolean;
|
||||
mode?: Mode;
|
||||
@@ -227,6 +229,10 @@ export function parseArgs(inputArgs: string[], extensionFlags?: Map<string, { ty
|
||||
result.alias = arg.slice("--alias=".length);
|
||||
} else if (arg === "--continue" || arg === "-c") {
|
||||
result.continue = true;
|
||||
} else if (arg === "--from-claude") {
|
||||
result.fromClaude = true;
|
||||
} else if (arg === "--from-codex") {
|
||||
result.fromCodex = true;
|
||||
} else if (arg === "--no-session") {
|
||||
result.noSession = true;
|
||||
} else if (arg === "--no-tools") {
|
||||
|
||||
@@ -290,6 +290,8 @@ export const VALUELESS_FLAGS: ReadonlySet<string> = new Set([
|
||||
"--version",
|
||||
"--allow-home",
|
||||
"--continue",
|
||||
"--from-claude",
|
||||
"--from-codex",
|
||||
"--no-session",
|
||||
"--no-tools",
|
||||
"--no-lsp",
|
||||
|
||||
@@ -6,16 +6,26 @@ import type { SessionInfo } from "../session/session-listing";
|
||||
import { SessionManager } from "../session/session-manager";
|
||||
import { FileSessionStorage } from "../session/session-storage";
|
||||
|
||||
/** Presentation and capability controls for the standalone session picker. */
|
||||
export interface SessionPickerOptions {
|
||||
allSessions?: SessionInfo[];
|
||||
title?: string;
|
||||
scopeLabel?: string | false;
|
||||
showCwd?: boolean;
|
||||
allowDelete?: boolean;
|
||||
allowGlobalScope?: boolean;
|
||||
historySearch?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the TUI session selector and return the selected session, or null if
|
||||
* cancelled. Rendered as a fullscreen overlay on the terminal's alternate
|
||||
* screen, so the list scrolls and rows are clickable with the mouse. Tab
|
||||
* toggles between current-folder and all-projects scope; the all-projects list
|
||||
* is loaded lazily via `SessionManager.listAll`.
|
||||
* cancelled. The default OMP picker supports deletion, transcript-history
|
||||
* search, and an all-projects scope; foreign import pickers disable those
|
||||
* source-owned capabilities.
|
||||
*/
|
||||
export async function selectSession(
|
||||
sessions: SessionInfo[],
|
||||
options?: { allSessions?: SessionInfo[] },
|
||||
options: SessionPickerOptions = {},
|
||||
): Promise<SessionInfo | null> {
|
||||
const { promise, resolve } = Promise.withResolvers<SessionInfo | null>();
|
||||
const ui = new TUI(new ProcessTerminal());
|
||||
@@ -26,11 +36,13 @@ export async function selectSession(
|
||||
// session-list prefix never sees. Best-effort: a missing/locked history.db
|
||||
// must not break the picker.
|
||||
let historyMatcher: ((query: string) => string[]) | undefined;
|
||||
try {
|
||||
const history = HistoryStorage.open();
|
||||
historyMatcher = (query: string) => history.matchingSessionIds(query);
|
||||
} catch (error) {
|
||||
logger.warn("History storage unavailable for session ranking", { error: String(error) });
|
||||
if (options.historySearch !== false) {
|
||||
try {
|
||||
const history = HistoryStorage.open();
|
||||
historyMatcher = (query: string) => history.matchingSessionIds(query);
|
||||
} catch (error) {
|
||||
logger.warn("History storage unavailable for session ranking", { error: String(error) });
|
||||
}
|
||||
}
|
||||
|
||||
const showSelector = () => {
|
||||
@@ -58,16 +70,21 @@ export async function selectSession(
|
||||
}
|
||||
},
|
||||
{
|
||||
onDelete: async (session: SessionInfo) => {
|
||||
// Delete handler - SessionList will show confirmation internally
|
||||
await storage.deleteSessionWithArtifacts(session.path);
|
||||
return true;
|
||||
},
|
||||
onDelete:
|
||||
options.allowDelete === false
|
||||
? undefined
|
||||
: async (session: SessionInfo) => {
|
||||
await storage.deleteSessionWithArtifacts(session.path);
|
||||
return true;
|
||||
},
|
||||
historyMatcher,
|
||||
loadAllSessions: () => SessionManager.listAll(storage),
|
||||
allSessions: options?.allSessions,
|
||||
loadAllSessions: options.allowGlobalScope === false ? undefined : () => SessionManager.listAll(storage),
|
||||
allSessions: options.allSessions,
|
||||
getTerminalRows: () => ui.terminal.rows,
|
||||
fillHeight: true,
|
||||
title: options.title,
|
||||
scopeLabel: options.scopeLabel,
|
||||
showCwd: options.showCwd,
|
||||
},
|
||||
);
|
||||
return selector;
|
||||
|
||||
Reference in New Issue
Block a user