Initial public release

This commit is contained in:
Bohdan Triapitsyn
2025-12-07 19:32:53 +02:00
commit 4b2edf7318
319 changed files with 81600 additions and 0 deletions
+152
View File
@@ -0,0 +1,152 @@
import { create } from "zustand";
import { devtools, persist, createJSONStorage } from "zustand/middleware";
import { opencodeClient } from "@/lib/opencode/client";
import type { Permission, PermissionResponse } from "@/types/permission";
import { isEditPermissionType, getAgentDefaultEditPermission } from "./utils/permissionUtils";
import { getSafeStorage } from "./utils/safeStorage";
import { useMessageStore } from "./messageStore";
import { useSessionStore } from "./sessionStore";
interface PermissionState {
permissions: Map<string, Permission[]>;
}
interface PermissionActions {
addPermission: (permission: Permission, contextData?: { currentAgentContext?: Map<string, string>, sessionAgentSelections?: Map<string, string>, getSessionAgentEditMode?: (sessionId: string, agentName: string | undefined) => string }) => void;
respondToPermission: (sessionId: string, permissionId: string, response: PermissionResponse) => Promise<void>;
}
type PermissionStore = PermissionState & PermissionActions;
const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null;
const sanitizePermissionEntries = (value: unknown): Array<[string, Permission[]]> => {
if (!Array.isArray(value)) {
return [];
}
const entries: Array<[string, Permission[]]> = [];
value.forEach((entry) => {
if (!Array.isArray(entry) || entry.length !== 2) {
return;
}
const [sessionId, permissions] = entry;
if (typeof sessionId !== "string" || !Array.isArray(permissions)) {
return;
}
entries.push([sessionId, permissions as Permission[]]);
});
return entries;
};
const executeWithPermissionDirectory = async <T>(sessionId: string, operation: () => Promise<T>): Promise<T> => {
try {
const sessionStore = useSessionStore.getState();
const metadata = sessionStore.getWorktreeMetadata(sessionId);
if (metadata?.path) {
return opencodeClient.withDirectory(metadata.path, operation);
}
const session = sessionStore.sessions.find((entry) => entry.id === sessionId) as { directory?: string } | undefined;
const directory =
typeof session?.directory === 'string' && session.directory.length > 0 ? session.directory : undefined;
if (directory) {
return opencodeClient.withDirectory(directory, operation);
}
} catch (error) {
console.warn('Failed to resolve session directory for permission handling:', error);
}
return operation();
};
export const usePermissionStore = create<PermissionStore>()(
devtools(
persist(
(set, get) => ({
permissions: new Map(),
addPermission: (permission: Permission, contextData?: { currentAgentContext?: Map<string, string>, sessionAgentSelections?: Map<string, string>, getSessionAgentEditMode?: (sessionId: string, agentName: string | undefined) => string }) => {
const sessionId = permission.sessionID;
if (!sessionId) {
return;
}
const permissionType = permission.type?.toLowerCase?.() ?? null;
let agentName = contextData?.currentAgentContext?.get(sessionId);
if (!agentName) {
agentName = contextData?.sessionAgentSelections?.get(sessionId) ?? undefined;
}
if (!agentName) {
if (typeof window !== "undefined") {
const configStore = window.__zustand_config_store__;
if (configStore?.getState) {
agentName = configStore.getState().currentAgentName ?? undefined;
}
}
}
const defaultMode = getAgentDefaultEditPermission(agentName);
const effectiveMode = contextData?.getSessionAgentEditMode?.(sessionId, agentName) ?? defaultMode;
const shouldAutoApprove = effectiveMode === 'full'
|| (effectiveMode === 'allow' && isEditPermissionType(permissionType));
if (shouldAutoApprove) {
get().respondToPermission(sessionId, permission.id, 'once').catch(() => {
});
return;
}
set((state) => {
const sessionPermissions = state.permissions.get(sessionId) || [];
const newPermissions = new Map(state.permissions);
newPermissions.set(sessionId, [...sessionPermissions, permission]);
return { permissions: newPermissions };
});
},
respondToPermission: async (sessionId: string, permissionId: string, response: PermissionResponse) => {
await executeWithPermissionDirectory(sessionId, () => opencodeClient.respondToPermission(sessionId, permissionId, response));
if (response === 'reject') {
const messageStore = useMessageStore.getState();
await messageStore.abortCurrentOperation(sessionId);
}
set((state) => {
const sessionPermissions = state.permissions.get(sessionId) || [];
const updatedPermissions = sessionPermissions.filter((p) => p.id !== permissionId);
const newPermissions = new Map(state.permissions);
newPermissions.set(sessionId, updatedPermissions);
return { permissions: newPermissions };
});
},
}),
{
name: "permission-store",
storage: createJSONStorage(() => getSafeStorage()),
partialize: (state) => ({
permissions: Array.from(state.permissions.entries()),
}),
merge: (persistedState, currentState) => {
if (!isRecord(persistedState)) {
return currentState;
}
const entries = sanitizePermissionEntries(persistedState.permissions);
return {
...currentState,
permissions: new Map(entries),
};
},
}
),
{
name: "permission-store",
}
)
);