mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-24 04:52:43 -07:00
feat(cli): support extension installation for teleportation
This commit is contained in:
@@ -51,6 +51,7 @@ import {
|
||||
type HookDefinition,
|
||||
type HookEventName,
|
||||
type ResolvedExtensionSetting,
|
||||
type TrajectoryProvider,
|
||||
coreEvents,
|
||||
applyAdminAllowlist,
|
||||
getAdminBlockedMcpServersMessage,
|
||||
@@ -957,6 +958,23 @@ Would you like to attempt to install via "git clone" instead?`,
|
||||
);
|
||||
}
|
||||
|
||||
let trajectoryProviderModule: TrajectoryProvider | undefined;
|
||||
if (config.trajectoryProvider) {
|
||||
try {
|
||||
const expectedPath = path.resolve(
|
||||
effectiveExtensionPath,
|
||||
config.trajectoryProvider,
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
trajectoryProviderModule = (await import(expectedPath))
|
||||
.default as TrajectoryProvider;
|
||||
} catch (e) {
|
||||
debugLogger.warn(
|
||||
`Failed to import trajectoryProvider at ${config.trajectoryProvider} for extension ${config.name}: ${getErrorMessage(e)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: config.name,
|
||||
version: config.version,
|
||||
@@ -980,6 +998,7 @@ Would you like to attempt to install via "git clone" instead?`,
|
||||
rules,
|
||||
checkers,
|
||||
plan: config.plan,
|
||||
trajectoryProviderModule,
|
||||
};
|
||||
} catch (e) {
|
||||
const extName = path.basename(extensionDir);
|
||||
|
||||
@@ -46,6 +46,11 @@ export interface ExtensionConfig {
|
||||
* Used to migrate an extension to a new repository source.
|
||||
*/
|
||||
migratedTo?: string;
|
||||
/**
|
||||
* Path to a module that implements the TrajectoryProvider interface.
|
||||
* Used for importing binary chat histories like Jetski Teleportation.
|
||||
*/
|
||||
trajectoryProvider?: string;
|
||||
}
|
||||
|
||||
export interface ExtensionUpdateInfo {
|
||||
|
||||
@@ -242,6 +242,50 @@ export abstract class ExtensionLoader {
|
||||
await this.stopExtension(extension);
|
||||
await this.startExtension(extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent session from all extensions if it's within the threshold.
|
||||
*/
|
||||
async getRecentExternalSession(
|
||||
workspaceUri?: string,
|
||||
thresholdMs: number = 10 * 60 * 1000,
|
||||
): Promise<{ prefix: string; id: string; displayName?: string } | null> {
|
||||
const activeExtensions = this.getExtensions().filter((e) => e.isActive);
|
||||
let mostRecent: {
|
||||
prefix: string;
|
||||
id: string;
|
||||
displayName?: string;
|
||||
mtime: number;
|
||||
} | null = null;
|
||||
|
||||
for (const extension of activeExtensions) {
|
||||
if (extension.trajectoryProviderModule) {
|
||||
try {
|
||||
const sessions =
|
||||
await extension.trajectoryProviderModule.listSessions(workspaceUri);
|
||||
for (const s of sessions) {
|
||||
const mtime = new Date(s.mtime).getTime();
|
||||
if (!mostRecent || mtime > mostRecent.mtime) {
|
||||
mostRecent = {
|
||||
prefix: extension.trajectoryProviderModule.prefix || '',
|
||||
id: s.id,
|
||||
displayName: s.displayName,
|
||||
mtime,
|
||||
};
|
||||
}
|
||||
}
|
||||
} catch (_e) {
|
||||
// Ignore extension errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mostRecent && Date.now() - mostRecent.mtime < thresholdMs) {
|
||||
return mostRecent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ExtensionEvents {
|
||||
|
||||
Reference in New Issue
Block a user