* feat: clone GitHub repo into a workspace Add an end-to-end "clone a GitHub repo and register it as a Paseo workspace" flow: a new workspace.github.clone RPC, daemon handler, client method, CLI `paseo clone` command, and a GitHub-repo mode in the project picker modal. Gated behind the workspaceGithubClone server capability flag. - protocol: workspace.github.clone request/response schemas + feature flag - server: handleWorkspaceGithubCloneRequest, normalizeCloneRepository - client: DaemonClient.cloneGithubWorkspace - cli: `paseo clone <repo> --dir <path> [--protocol https|ssh]` - app: GitHub-repo mode, clone-protocol picker, error surfacing Review fixes: - CLI clone now checks the workspaceGithubClone capability and fails fast with a clear "update the host" error instead of hanging for the full request timeout against an older daemon. - Replace the duplicated client-side URL-detection regex (app + CLI) with a shared isCompleteGitRemote() in @getpaseo/protocol/git-remote, backed by parseGitRemoteLocation so clients classify remotes identically to the daemon (fixes confusing errors for git://, ftp://, file:// inputs). - Add git-remote.test.ts covering the shared classifier. * Fix GitHub clone failure handling --------- Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
96 lines
3.0 KiB
TypeScript
96 lines
3.0 KiB
TypeScript
import { useCallback } from "react";
|
|
import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime";
|
|
import { useSessionStore } from "@/stores/session-store";
|
|
import { useWorkspaceLayoutStore } from "@/stores/workspace-layout-store";
|
|
import { generateDraftId } from "@/stores/draft-keys";
|
|
import { navigateToWorkspace } from "@/stores/navigation-active-workspace-store";
|
|
import {
|
|
openGithubRepoDirectly,
|
|
openProjectDirectly,
|
|
type OpenProjectResult,
|
|
type WorkspaceGithubCloneProtocol,
|
|
} from "@/hooks/open-project";
|
|
|
|
export function useOpenProject(
|
|
serverId: string | null,
|
|
): (path: string) => Promise<OpenProjectResult> {
|
|
const normalizedServerId = serverId?.trim() ?? "";
|
|
const client = useHostRuntimeClient(normalizedServerId);
|
|
const isConnected = useHostRuntimeIsConnected(normalizedServerId);
|
|
const canAddProject = useSessionStore((state) =>
|
|
normalizedServerId
|
|
? state.sessions[normalizedServerId]?.serverInfo?.features?.projectAdd === true
|
|
: false,
|
|
);
|
|
const addEmptyProject = useSessionStore((state) => state.addEmptyProject);
|
|
const setHasHydratedWorkspaces = useSessionStore((state) => state.setHasHydratedWorkspaces);
|
|
|
|
return useCallback(
|
|
async (path: string) => {
|
|
const result = await openProjectDirectly({
|
|
serverId: normalizedServerId,
|
|
projectPath: path,
|
|
isConnected,
|
|
canAddProject,
|
|
client,
|
|
addEmptyProject,
|
|
setHasHydratedWorkspaces,
|
|
});
|
|
return result;
|
|
},
|
|
[
|
|
addEmptyProject,
|
|
canAddProject,
|
|
client,
|
|
isConnected,
|
|
normalizedServerId,
|
|
setHasHydratedWorkspaces,
|
|
],
|
|
);
|
|
}
|
|
|
|
export function useOpenGithubRepo(
|
|
serverId: string | null,
|
|
): (
|
|
repo: string,
|
|
targetDirectory: string,
|
|
cloneProtocol?: WorkspaceGithubCloneProtocol,
|
|
) => Promise<boolean> {
|
|
const normalizedServerId = serverId?.trim() ?? "";
|
|
const client = useHostRuntimeClient(normalizedServerId);
|
|
const isConnected = useHostRuntimeIsConnected(normalizedServerId);
|
|
const mergeWorkspaces = useSessionStore((state) => state.mergeWorkspaces);
|
|
const setHasHydratedWorkspaces = useSessionStore((state) => state.setHasHydratedWorkspaces);
|
|
const openDraftTab = useCallback((workspaceKey: string) => {
|
|
return useWorkspaceLayoutStore.getState().openTabFocused(workspaceKey, {
|
|
kind: "draft",
|
|
draftId: generateDraftId(),
|
|
});
|
|
}, []);
|
|
|
|
return useCallback(
|
|
async (repo: string, targetDirectory: string, cloneProtocol?: WorkspaceGithubCloneProtocol) => {
|
|
return openGithubRepoDirectly({
|
|
serverId: normalizedServerId,
|
|
repo,
|
|
targetDirectory,
|
|
...(cloneProtocol ? { cloneProtocol } : {}),
|
|
isConnected,
|
|
client,
|
|
mergeWorkspaces,
|
|
setHasHydratedWorkspaces,
|
|
openDraftTab,
|
|
navigateToWorkspace,
|
|
});
|
|
},
|
|
[
|
|
client,
|
|
isConnected,
|
|
mergeWorkspaces,
|
|
normalizedServerId,
|
|
openDraftTab,
|
|
setHasHydratedWorkspaces,
|
|
],
|
|
);
|
|
}
|