94 lines
3.0 KiB
TypeScript
94 lines
3.0 KiB
TypeScript
import type { Session } from '@opencode-ai/sdk/v2';
|
|
import type { Part } from '@opencode-ai/sdk/v2/client';
|
|
import { notifyGitStatusInvalidated } from '@/lib/gitStatusInvalidation';
|
|
import type { WorktreeMetadata } from '@/types/worktree';
|
|
|
|
export type SessionDeleteRequest = {
|
|
sessions: Session[];
|
|
dateLabel?: string;
|
|
mode?: 'session' | 'worktree';
|
|
worktree?: WorktreeMetadata | null;
|
|
};
|
|
|
|
export type SessionCreateRequest = {
|
|
worktreeMode?: 'main' | 'create' | 'reuse';
|
|
parentID?: string | null;
|
|
projectId?: string | null;
|
|
};
|
|
|
|
type DeleteListener = (request: SessionDeleteRequest) => void;
|
|
type CreateListener = (request: SessionCreateRequest) => void;
|
|
type DirectoryListener = () => void;
|
|
type GitRefreshHint = { directory: string; paths?: string[] };
|
|
type GitRefreshListener = (hint: GitRefreshHint) => void;
|
|
|
|
const deleteListeners = new Set<DeleteListener>();
|
|
const createListeners = new Set<CreateListener>();
|
|
const directoryListeners = new Set<DirectoryListener>();
|
|
const gitRefreshListeners = new Set<GitRefreshListener>();
|
|
const gitMutatingTools = new Set(['bash', 'edit', 'write', 'apply_patch', 'patch']);
|
|
|
|
const normalizeToolName = (tool: string): string => {
|
|
const parts = tool.trim().toLowerCase().split('.').filter(Boolean);
|
|
return parts[parts.length - 1] ?? '';
|
|
};
|
|
|
|
export const sessionEvents = {
|
|
onDeleteRequest(listener: DeleteListener) {
|
|
deleteListeners.add(listener);
|
|
return () => {
|
|
deleteListeners.delete(listener);
|
|
};
|
|
},
|
|
requestDelete(payload: SessionDeleteRequest) {
|
|
if (!payload.sessions.length && payload.mode !== 'worktree') {
|
|
return;
|
|
}
|
|
deleteListeners.forEach((listener) => listener(payload));
|
|
},
|
|
onCreateRequest(listener: CreateListener) {
|
|
createListeners.add(listener);
|
|
return () => {
|
|
createListeners.delete(listener);
|
|
};
|
|
},
|
|
requestCreate(payload?: SessionCreateRequest) {
|
|
const request = payload ?? {};
|
|
createListeners.forEach((listener) => listener(request));
|
|
},
|
|
onDirectoryRequest(listener: DirectoryListener) {
|
|
directoryListeners.add(listener);
|
|
return () => {
|
|
directoryListeners.delete(listener);
|
|
};
|
|
},
|
|
requestDirectoryDialog() {
|
|
directoryListeners.forEach((listener) => listener());
|
|
},
|
|
onGitRefreshHint(listener: GitRefreshListener) {
|
|
gitRefreshListeners.add(listener);
|
|
return () => {
|
|
gitRefreshListeners.delete(listener);
|
|
};
|
|
},
|
|
requestGitRefresh(hint: GitRefreshHint) {
|
|
if (!hint.directory.trim()) {
|
|
return;
|
|
}
|
|
notifyGitStatusInvalidated(hint.directory);
|
|
gitRefreshListeners.forEach((listener) => listener(hint));
|
|
},
|
|
requestGitRefreshForToolTransition(directory: string, previousPart: Part | undefined, nextPart: Part) {
|
|
if (nextPart.type !== 'tool' || nextPart.state.status !== 'completed') {
|
|
return;
|
|
}
|
|
if (previousPart?.type === 'tool' && previousPart.state.status === 'completed') {
|
|
return;
|
|
}
|
|
if (!gitMutatingTools.has(normalizeToolName(nextPart.tool))) {
|
|
return;
|
|
}
|
|
sessionEvents.requestGitRefresh({ directory });
|
|
},
|
|
};
|